普遍逻辑
创建一个 socket 绑定端口,用于监听。
使用 fd = accept(socket_fd, &addr, &addr_len);
一旦有握手的tcp连接,就建立一个新的socket,并且开新的线程。线程中会利用这个 socket的fd 进行交互。对于各种请求进行处理。
调试\交互方式
个人用的方法:
server = process(filename) |
可能每次请求都要建立一个新的remote
因此建议每次都p.close()
关键部分
通常需要重点关注处理请求部分,也就是handler。
有可能是溢出 ,还有可能是竞争。
利用手法
在/bin/sh基础上 可能还需要 dup2 定向stdout stdin stderr 到本socket
有些程序要打orw 可以用sendfile 的方式来做。
Syncvault
程序逆向
程序主要功能是维护任务队列,worker模拟任务运行,并且实现多种查询功能。并且加了一个和主要逻辑关系不大的功能 SYNC。
main
main中,两个start_routine 开worker线程,worker线程会等 task排入queue,然后给出对应输出。
然后就是开 socket ,对输入进行对应处理 ,然后输出。
SET_
设置 echo 的size,最大只能到0x400
SETHEAD_
设置 head 的 size , 最大只能到0x400
SETBODY_
…
SETSYNC_
…
ECHO
输出 echo size 大小的输入内容。
SNAPSHOT
按照HHH…..PPPPP…这种形式 输出HEAD 和 BODY的内容。
GAID
输出一些线程有关内容。
QUEUE ???
在队列中增加任务。
SHOW TASKS
输出任务
SHOW LOGS
输出日志
TICK
输出统计内容
QUIT
退出
SYNC
奇怪的函数 但是可以发现有明显的溢出
if ( (unsigned __int64)syncnum > 0x38 ) |
而s根本就没有0x38
v38 = 0; |
后面的复制部分明显可以覆盖到v61
利用
通过搜寻set_robust_list相关功能。
可以发现,线程退出时,会把robust_list每个节点对应的mutex(用mutex offset) 用 OWNER_DIED 进行标记,这个标记可以修改mutex为一个很大的值。前提是修改时能通过检查(mutex正好是tid)
而SNAPSHOT和ECHO功能都和size有关,并且都莫名奇妙的给出>0x1000时的处理方式,而正常根本不会>0x1000。并且0x1000是很大的溢出。那么目的应该就是通过上述的漏洞,先伪造成tid,然后覆盖成一个很大的值,实现溢出读取和溢出写入。
这题本地调的时候有个困难 就是pid太大 就打不了了 。
询问ai后了解到,可以用 unshare用新的pid ns开进程
server = process( |
def listen_pid(port: int): |
这个函数可以找进程pid 便于调试
from elftools.construct.lib.container import recursion_lock |
minihttpd
较为正常的 get 和 post 处理
对post的处理方式比较用意思,用了driver的方式
void __fastcall bindrequest() |
void __fastcall writerequest(char *a1, char *a2, void *a3) |
handle = finddriver(path, method_buffer); |
漏洞在setmode部分的溢出
int __fastcall setmode(int a1, const char *a2, int a3) |
from pwn import * |
