0


ctf夺旗赛

web

第三个空白页

抓包,然后查看源码,

访问一下way=AHAHAH这个子目录

然后构造X-Forwarded-For: 127.0.0.1伪造ip成本地访问,

然后得到flag

控制中心的密码

一开始根据这个题目内容的描述我还以为是要进行爆破,但是又有验证码,所以我也是束手无策,后来摸索发现结果并不用爆破。

先登录和后台,在点击flag的位置抓包,

将1000改为1,上传,于是得到flag

又是空白页面

这个题目是最简单的,直接在检查里面就能看到flag

你就是长不了

这个题目也是简单抓包就可以,直接在包里面将长度改长就能跳出flag,

reverse

后门查杀

这个题目很简单,直接用d盾扫一下就能扫出后面,不想再下载附件了所以就讲思路得了

reverse1

这题能直接百度得到wp,

准备

获得信息

64位文件

x64dbg打开

搜索全部字符串

打开红框中字符串的位置

复制代码

 1 00007FF7F26F18FD | 8945 04                  | mov dword ptr ss:[rbp+4],eax            |
 2 00007FF7F26F1900 | 48:6345 04               | movsxd rax,dword ptr ss:[rbp+4]         |
 3 00007FF7F26F1904 | 48:8985 08010000         | mov qword ptr ss:[rbp+108],rax          |
 4 00007FF7F26F190B | 48:8D0D EEA60000         | lea rcx,qword ptr ds:[7FF7F26FC000]     | 00007FF7F26FC000:"{hello_world}"
 5 00007FF7F26F1912 | E8 8DF8FFFF              | call reverse_1.7FF7F26F11A4             |
 6 00007FF7F26F1917 | 48:8B8D 08010000         | mov rcx,qword ptr ss:[rbp+108]          |
 7 00007FF7F26F191E | 48:3BC8                  | cmp rcx,rax                             |
 8 00007FF7F26F1921 | 77 25                    | ja reverse_1.7FF7F26F1948               |
 9 00007FF7F26F1923 | 48:6345 04               | movsxd rax,dword ptr ss:[rbp+4]         |
10 00007FF7F26F1927 | 48:8D0D D2A60000         | lea rcx,qword ptr ds:[7FF7F26FC000]     | 00007FF7F26FC000:"{hello_world}"
11 00007FF7F26F192E | 0FBE0401                 | movsx eax,byte ptr ds:[rcx+rax]         |
12 00007FF7F26F1932 | 83F8 6F                  | cmp eax,6F                              | 6F:'o'
13 00007FF7F26F1935 | 75 0F                    | jne reverse_1.7FF7F26F1946              |
14 00007FF7F26F1937 | 48:6345 04               | movsxd rax,dword ptr ss:[rbp+4]         |
15 00007FF7F26F193B | 48:8D0D BEA60000         | lea rcx,qword ptr ds:[7FF7F26FC000]     | 00007FF7F26FC000:"{hello_world}"
16 00007FF7F26F1942 | C60401 30                | mov byte ptr ds:[rcx+rax],30            | 30:'0'
17 00007FF7F26F1946 | EB B0                    | jmp reverse_1.7FF7F26F18F8              |
18 00007FF7F26F1948 | 48:8D0D E1830000         | lea rcx,qword ptr ds:[7FF7F26F9D30]     | 00007FF7F26F9D30:"input the flag:"
19 00007FF7F26F194F | E8 7DF8FFFF              | call reverse_1.7FF7F26F11D1             |
20 00007FF7F26F1954 | 48:8D55 28               | lea rdx,qword ptr ss:[rbp+28]           |
21 00007FF7F26F1958 | 48:8D0D C5830000         | lea rcx,qword ptr ds:[7FF7F26F9D24]     | 00007FF7F26F9D24:"%20s"
22 00007FF7F26F195F | E8 2BF9FFFF              | call reverse_1.7FF7F26F128F             |
23 00007FF7F26F1964 | 48:8D0D 95A60000         | lea rcx,qword ptr ds:[7FF7F26FC000]     | 00007FF7F26FC000:"{hello_world}"
24 00007FF7F26F196B | E8 34F8FFFF              | call reverse_1.7FF7F26F11A4             |
25 00007FF7F26F1970 | 4C:8BC0                  | mov r8,rax                              |
26 00007FF7F26F1973 | 48:8D15 86A60000         | lea rdx,qword ptr ds:[7FF7F26FC000]     | 00007FF7F26FC000:"{hello_world}"
27 00007FF7F26F197A | 48:8D4D 28               | lea rcx,qword ptr ss:[rbp+28]           |
28 00007FF7F26F197E | FF15 4CE90000            | call qword ptr ds:[<&strncmp>]          |
29 00007FF7F26F1984 | 85C0                     | test eax,eax                            |
30 00007FF7F26F1986 | 74 0E                    | je reverse_1.7FF7F26F1996               |
31 00007FF7F26F1988 | 48:8D0D 81820000         | lea rcx,qword ptr ds:[7FF7F26F9C10]     | 00007FF7F26F9C10:"wrong flag\n"
32 00007FF7F26F198F | E8 3DF8FFFF              | call reverse_1.7FF7F26F11D1             |
33 00007FF7F26F1994 | EB 0C                    | jmp reverse_1.7FF7F26F19A2              |
34 00007FF7F26F1996 | 48:8D0D F3820000         | lea rcx,qword ptr ds:[7FF7F26F9C90]     | 00007FF7F26F9C90:"this is the right flag!\n"
35 00007FF7F26F199D | E8 2FF8FFFF              | call reverse_1.7FF7F26F11D1             |

代码分析

第28行代码调用了strcmp比较输入字符串与“{hello_world}”,这个“{hello_world}”似乎就是我们的flag。

在"input the flag"上面,分析代码,了解到此部分对“{hello_world}”进行了'o'字符替换为‘0’字符的操作。因此得到正确答案为“{hell0_w0rld}”

get flag!

flag{hell0_w0rld}

刮开有奖

本题直接能在百度上搜到,

进入主函数WinMain

int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
  DialogBoxParamA(hInstance, (LPCSTR)0x67, 0, DialogFunc, 0);
  return 0;
}

找到关键的函数DialogFunc,并反编译为C代码

 1 BOOL __userpurge DialogFunc@<eax>(int a1@<edi>, int a2@<esi>, HWND hDlg, UINT a4, WPARAM a5, LPARAM a6)
 2 {
 3   const char *v6; // esi
 4   const char *v7; // edi
 5   int v9; // [esp+4h] [ebp-20030h]
 6   int v10; // [esp+8h] [ebp-2002Ch]
 7   int v11; // [esp+Ch] [ebp-20028h]
 8   int v12; // [esp+10h] [ebp-20024h]
 9   int v13; // [esp+14h] [ebp-20020h]
10   int v14; // [esp+18h] [ebp-2001Ch]
11   int v15; // [esp+1Ch] [ebp-20018h]
12   int v16; // [esp+20h] [ebp-20014h]
13   int v17; // [esp+24h] [ebp-20010h]
14   int v18; // [esp+28h] [ebp-2000Ch]
15   int v19; // [esp+2Ch] [ebp-20008h]
16   CHAR String; // [esp+30h] [ebp-20004h]
17   char v21; // [esp+31h] [ebp-20003h]
18   char v22; // [esp+32h] [ebp-20002h]
19   char v23; // [esp+33h] [ebp-20001h]
20   char v24; // [esp+34h] [ebp-20000h]
21   char v25; // [esp+10030h] [ebp-10004h]
22   char v26; // [esp+10031h] [ebp-10003h]
23   char v27; // [esp+10032h] [ebp-10002h]
24   int v28; // [esp+20028h] [ebp-Ch]
25   int v29; // [esp+2002Ch] [ebp-8h]
26 
27   __alloca_probe();
28   if ( a4 == 272 )
29     return 1;
30   v29 = a2;
31   v28 = a1;
32   if ( a4 != 273 )
33     return 0;
34   if ( (_WORD)a5 == 1001 )
35   {
36     memset(&String, 0, 0xFFFFu);
37     GetDlgItemTextA(hDlg, 1000, &String, 0xFFFF);
38     if ( strlen(&String) == 8 )
39     {
40       v9 = 90;
41       v10 = 74;
42       v11 = 83;
43       v12 = 69;
44       v13 = 67;
45       v14 = 97;
46       v15 = 78;
47       v16 = 72;
48       v17 = 51;
49       v18 = 110;
50       v19 = 103;
51       sub_4010F0(&v9, 0, 10);
52       memset(&v25, 0, 0xFFFFu);
53       v6 = (const char *)sub_401000(&v25, strlen(&v25));
54       memset(&v25, 0, 0xFFFFu);
55       v26 = v23;
56       v25 = v22;
57       v27 = v24;
58       v7 = (const char *)sub_401000(&v25, strlen(&v25));
59       if ( String == v9 + 34
60         && v21 == v13
61         && 4 * v22 - 141 == 3 * v11
62         && v23 / 4 == 2 * (v16 / 9)
63         && !strcmp(v6, "ak1w")
64         && !strcmp(v7, "V1Ax") )
65       {
66         MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0);
67       }
68     }
69     return 0;
70   }
71   if ( (_WORD)a5 != 1 && (_WORD)a5 != 2 )
72     return 0;
73   EndDialog(hDlg, (unsigned __int16)a5);
74   return 1;
75 }
  1. 代码分析

3.1 字符串解析

通过第37行代码GetDlgItemTextA,我们知道了String是我们输入的flag。

通过第38行代码我们知道flag的长度应该是8

第51行函数sub_4010F0在对v9v19进行某种操作,进入sub_4010F0函数,将函数转换为C语言代码,再将v9v19代入

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
​
using namespace std;
​
int __cdecl sub_4010F0(char *a1, int a2, int a3)
{
    int result; // eax
    int i; // esi
    int v5; // ecx
    int v6; // edx
​
    result = a3;
    for (i = a2; i <= a3; a2 = i)
    {
        v5 = i;
        v6 = a1[i];
        if (a2 < result && i < result)
        {
            do
            {
                if (v6 >a1[result])
                {
                    if (i >= result)
                        break;
                    ++i;
                    a1[v5] = a1[result];
                    if (i >= result)
                        break;
                    while (a1[i] <= v6)
                    {
                        if (++i >= result)
                            goto LABEL_13;
                    }
                    if (i >= result)
                        break;
                    v5 = i;
                    a1[result] = a1[i];
                }
                --result;
            } while (i < result);
        }
    LABEL_13:
        a1[result] = v6;
        sub_4010F0(a1, a2, i - 1);
        result = a3;
        ++i;
    }
    return result;
}
​
char str[20] = { 90,74,83,69,67,97,78,72,51,110,103 };
​
int main()
{
    cout << str << endl;
​
    sub_4010F0(str, 0, 10);
​
    for (int i = 0; i < 11; ++i) {
        cout << str[i];
    }
    return 0;
}

输出

3.2 字符串加密

分析第52行代码~58行代码。我们转到汇编代码处

.text:004012B0                 push    0FFFFh          ; size_t
.text:004012B5                 lea     edx, [ebp+var_10004]
.text:004012BB                 push    0               ; int
.text:004012BD                 push    edx             ; void *
.text:004012BE                 call    _memset
.text:004012C3                 mov     al, [ebp+var_1FFFF]
.text:004012C9                 mov     dl, [ebp+var_1FFFD]
.text:004012CF                 mov     cl, [ebp+var_1FFFE]
.text:004012D5                 mov     [ebp+var_10004], al
.text:004012DB                 lea     eax, [ebp+var_10004]
.text:004012E1                 mov     [ebp+var_10002], dl
.text:004012E7                 add     esp, 18h
.text:004012EA                 mov     [ebp+var_10003], cl
.text:004012F0                 lea     edx, [eax+1]
.text:004012F3
.text:004012F3 loc_4012F3:                             ; CODE XREF: DialogFunc+158↓j
.text:004012F3                 mov     cl, [eax]
.text:004012F5                 inc     eax
.text:004012F6                 test    cl, cl
.text:004012F8                 jnz     short loc_4012F3
.text:004012FA                 sub     eax, edx
.text:004012FC                 push    eax
.text:004012FD                 lea     eax, [ebp+var_10004]
.text:00401303                 push    eax
.text:00401304                 call    sub_401000
.text:00401309                 push    0FFFFh          ; size_t
.text:0040130E                 lea     ecx, [ebp+var_10004]
.text:00401314                 push    0               ; int
.text:00401316                 push    ecx             ; void *
.text:00401317                 mov     esi, eax
.text:00401319                 call    _memset
.text:0040131E                 mov     al, [ebp+var_20001]
.text:00401324                 mov     dl, [ebp+var_20002]
.text:0040132A                 mov     cl, [ebp+var_20000]
.text:00401330                 mov     [ebp+var_10003], al
.text:00401336                 lea     eax, [ebp+var_10004]
.text:0040133C                 mov     [ebp+var_10004], dl
.text:00401342                 add     esp, 14h
.text:00401345                 mov     [ebp+var_10002], cl
.text:0040134B                 lea     edx, [eax+1]
.text:0040134E                 mov     edi, edi

看加粗加红处(下面是对应字符串的信息)

-00020004 String          db ?
-00020003 var_20003       db ?
-00020002 var_20002       db ?
-00020001 var_20001       db ?
-00020000 var_20000       db ?
-0001FFFF var_1FFFF       db ?
-0001FFFE var_1FFFE       db ?
-0001FFFD var_1FFFD       db ?

我们可以知道,v6使用sub_4010F0函数后的字符串的6,7,8位,调用sub_401000函数,v7使用sub_4010F0函数后的字符串的3,4,5位,调用sub_401000函数。

3.3 加密方式

进入sub_401000

 1 _BYTE *__cdecl sub_401000(int a1, int a2)
 2 {
 3   int v2; // eax
 4   int v3; // esi
 5   size_t v4; // ebx
 6   _BYTE *v5; // eax
 7   _BYTE *v6; // edi
 8   int v7; // eax
 9   _BYTE *v8; // ebx
10   int v9; // edi
11   signed int v10; // edx
12   int v11; // edi
13   signed int v12; // eax
14   signed int v13; // esi
15   _BYTE *result; // eax
16   _BYTE *v15; // [esp+Ch] [ebp-10h]
17   _BYTE *v16; // [esp+10h] [ebp-Ch]
18   int v17; // [esp+14h] [ebp-8h]
19   int v18; // [esp+18h] [ebp-4h]
20 
21   v2 = a2 / 3;
22   v3 = 0;
23   if ( a2 % 3 > 0 )
24     ++v2;
25   v4 = 4 * v2 + 1;
26   v5 = malloc(v4);
27   v6 = v5;
28   v15 = v5;
29   if ( !v5 )
30     exit(0);
31   memset(v5, 0, v4);
32   v7 = a2;
33   v8 = v6;
34   v16 = v6;
35   if ( a2 > 0 )
36   {
37     while ( 1 )
38     {
39       v9 = 0;
40       v10 = 0;
41       v18 = 0;
42       do
43       {
44         if ( v3 >= v7 )
45           break;
46         ++v10;
47         v9 = *(unsigned __int8 *)(v3++ + a1) | (v9 << 8);
48       }
49       while ( v10 < 3 );
50       v11 = v9 << 8 * (3 - v10);
51       v12 = 0;
52       v17 = v3;
53       v13 = 18;
54       do
55       {
56         if ( v10 >= v12 )
57         {
58           *((_BYTE *)&v18 + v12) = (v11 >> v13) & 0x3F;
59           v8 = v16;
60         }
61         else
62         {
63           *((_BYTE *)&v18 + v12) = 64;
64         }
65         *v8++ = byte_407830[*((char *)&v18 + v12)];
66         v13 -= 6;
67         ++v12;
68         v16 = v8;
69       }
70       while ( v13 > -6 );
71       v3 = v17;
72       if ( v17 >= a2 )
73         break;
74       v7 = a2;
75     }
76     v6 = v15;
77   }
78   result = v6;
79   *v8 = 0;
80   return result;
81 }

进入第65行byte_407830

.rdata:00407830 ; char byte_407830[]
.rdata:00407830 byte_407830     db 41h                  ; DATA XREF: sub_401000+C0↑r
.rdata:00407831 aBcdefghijklmno db 'BCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',0

我们可以猜测这个函数应该是base64加密。

3.4 flag分析

      if ( String == v9 + 34                    // sub_4010F0函数后的第一位等于51+34=85-->'U'
        && v21 == v13                           // 第2位,等于v13,即sub_4010F0函数返回值的第5位值-->'J'
        && 4 * v22 - 141 == 3 * v11
        && v23 / 4 == 2 * (v16 / 9)
        && !strcmp(v6, "ak1w")                  // 第6,7,8行代码base64之后,需要等于"ak1w"
        && !strcmp(                             // 第3,4,5行代码,加密之后等于V1Ax
              v7,
              "V1Ax") )
      {
        MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0);
      }

将v6,v7解密之后得到WP1jMp,再结合第1,2位得到flag

3.get flag!

flag{UJWP1jMp}

icekey

不太会,不过flag也能在百度上查到,不过得费一番功夫,

GAesDecode

\1. APK****文件静态反编译

使用JEB2反编译及查看JAVA代码(该题不涉及native层,IDA ARM反汇编及调试有机会再讲),“EP”定位可通过manifest查看

onCreate函数可看到很直接的加密流程:MainActivity.encrypt接受屏幕输入和一串字符;判断其返回值是否等于“**kNk3Qz+l/kLpGuKxf5iGE9cOoTmmn9Ac+UdF4b2CHqU=**”:

encrypt()函数传入的第二个参数“**This is a AES-like encryption algorithm. However, we do some change. Therefore, you cannot directly use security class to decrypt the message. Our challenge is to find the plain text of this encrypt message with th fixed key.**”

提示这是个变形的AES加密算法,可能是友善的也可能是误导,但后续我们可以此为依据进行验证加快解题速度。

\1. 尝试运行

使用雷电安卓模拟器,随意输入“12345678”,验证其错误信息输出

“Incorrect Flag!”:

\1. JEB2****调试

Debugger->Start->Attach:

使用特定函数调用(如本例Base64.encodeToSTring)从JAVA定位到Smali代码,Ctrl+B下断点:

标准加密与APK调试验证对比:

\1. 破解算法

先参考下(AES加密算法的详细介绍与实现_TimeShatter的博客-CSDN博客_aes)标准的AES加密流程图

APK算法首先对输入字串进行一个16分组,这里的变量名可通过快捷键n(类似IDA)重命名,帮助逆向理解:

对每16字符进行10轮变换

然后,做一个拼接(4是因为AES以4字节为一个单位):

最后对加密字串做base64输出。

对比关键的四个加密模块函数:字节代换substitute()、行移位shiftRows()、列混合mixCloumns()、轮密钥加addRoundKey()。

轮密钥加****addRoundKey():

轮密钥加是将128位轮密钥Ki同状态矩阵中的数据进行逐位异或操作,与apk代码相符;

字节代换****substitute():

可发现APK代码中的有现成的逆S盒与标准逆S盒一致,暂时可推断也使用标准S盒:

行移位****shiftRows():

行移位是一个简单的左循环移位操作。当密钥长度为128比特时,状态矩阵的第0行左移0字节,第1行左移1字节,第2行左移2字节,第3行左移3字节,与APK代码一致:

列混合****mixCloumns():

首先四次变换的逻辑没有问题:

2,3,1,1

1,2,3,1

1,1,2,3

3,1,1,2

LightState.add()也没有问题:

LightState.multiply2()发现异或值做了改变:

变形解密将“0x1b”改为“0x1d”配置好key及“kNk3Qz+l/kLpGuKxf5iGE9cOoTmmn9Ac+UdF4b2CHqU=”解密的16进制数

flag{aes_is_the_best_encryption}

杂项

hahaha

拿到题目发现是CRC32爆破,使用工具进行如下破解

得到压缩包密码为:

tanny_is_very_beautifu1_

解密后拿到flag.pdf,得到如下信息

需要我们进行排列组合,得到结果的Sha1为

e6079c5ce56e781a50f4bf853cdb5302e0d8f054

排列组合大致如下

1!2@{[}]asefcghnl

直接刚可能性太多,这里我们知道应该是flag{}样式,所以缩小范围为

1!2@sechn

编写如下脚本

import itertools
import hashlib

def sha1(str):
    sha = hashlib.sha1(str)
    encrypts = sha.hexdigest()
    return encrypts
a1 = '1!'
a2 = '2@'
a3 = '{'
a4 = '}'
for str1 in itertools.combinations(a1,1):
    for str2 in itertools.combinations(a2,1):
        str3 = str1[0]+str2[0]+'sechn'
        for i in itertools.permutations(str3):
            tmp = (''.join(i))
            res = 'flag{'+tmp+'}'
            # print sha1(res)
            if sha1(res) == 'e6079c5ce56e781a50f4bf853cdb5302e0d8f054':
                print res
                break

运行后得到flag

flag{sh@1enc}

再进行md5编码 947aed223b58dca829f38858116756c0

memory

这题随后求得密码是123456789

然后进行md5编码

Crypto

这里面的题目一般都在百度上直接能找到,这里就不过多阐述,

总结

此次比赛我主要是做web方向,完成情况也还不错,基本所以题上都是第一二个上交完成,其他题型的话基本上就是一个字摸,整体上来说完成情况还是不错的。


本文转载自: https://blog.csdn.net/m0_63017769/article/details/127817826
版权归原作者 xiu-1.0 所有, 如有侵权,请联系我们删除。

“ctf夺旗赛”的评论:

还没有评论