Attack and defense world XCTF reverse advanced area (continuous update)

Words written in the front

It's still a process of learning from the past and learning from the past. In addition, I hope I can finish the problem of more than 100 people in the advanced area earlier. Come on! (2020.6.2).

Ah, the questions in the advanced area often change. The previous questions may be transferred to the back, so the order may not be correct.


Get the program, it's a jar file, drag it into JD Jui to view, and you can directly see the main function. It can be seen that when the judgment is true, the flag will be output directly after exclusive or operation

My_ The value of number has been given directly, and the direct operation is to round down as the input

Or you can calculate the flag directly according to the value given by the program. I really can't write this code at present. I write it directly according to other people's code, and I'll change it when I have my own understanding

a = '4b64ca12ace755516c178f72d05d7061'
b = 'ecd44646cfe5994ebeb35bf922e25dba'
c = bytes.fromhex(a)
d = bytes.fromhex(b)
flag = [0] * 16
for i in range(len(c)):
  flag[i] = c[i] ^ d[i]
  flag[i] = hex(flag[i])


Through direct string search, we found that there was a flag, the submitted flag was wrong, and then cross referenced the string right all the way to find the main judgment function

Note that the input is in reverse order, and then there is a certain error in the disassembly of this question. v2 points to unknown, but it does not affect the problem, because it is easy to guess, and it is not difficult to understand after reading

.text:00401100 loc_401100:                             ; CODE XREF: sub_401080+8E↓j
.text:00401100                 mov     al, [esi]
.text:00401102                 lea     esi, [esi-1]
.text:00401105                 mov     byte_40336C[edx], al
.text:0040110B                 inc     edx
.text:0040110C                 cmp     edx, ecx
.text:0040110E                 jl      short loc_401100
.text:00401110                 pop     esi
.text:00401111 loc_401111:                             ; CODE XREF: sub_401080+6F↑j
.text:00401111                 xor     edx, edx
.text:00401113 loc_401113:                             ; CODE XREF: sub_401080+A6↓j
.text:00401113                 mov     al, byte_40336C[edx]
.text:00401119                 inc     al
.text:0040111B                 xor     al, 6
.text:0040111D                 mov     byte_40336C[edx], al
.text:00401123                 inc     edx
.text:00401124                 cmp     edx, ecx
.text:00401126                 jb      short loc_401113
.text:00401128                 mov     ecx, offset unk_402124
.text:0040112D                 mov     eax, offset byte_40336C

[failed to transfer the pictures in the external link. The source station may have anti-theft chain mechanism. It is recommended to save the pictures and upload them directly (img-m3ce91ow-1593054216962)( ]

Direct code:

cm = [0x78, 0x49, 0x72, 0x43, 0x6A, 0x7E, 0x3C, 0x72, 0x7C, 0x32, 
  0x74, 0x57, 0x73, 0x76, 0x33, 0x50, 0x74, 0x49, 0x7F, 0x7A, 
  0x6E, 0x64, 0x6B, 0x61]
flag = ''
for i in range(len(cm)):
	flag += chr((cm[i] ^ 6) - 1)


Check in the water bottle. According to the title description, we can see that a long column of characters given by the main function is to find the flag

cm = [83,69,67,67,79,78,123,87,101,108,99,111,109,101,32,116,111,32,116,104,101,32,83,69,67,67,79,78,32,50,48,49,52,32,67,84,70,33,125]
flag = ''
for i in range(len(cm)):
	flag += chr(cm[i])


Open and find that MIPS cannot be decompiled. You can consider A: Download plug-ins from the official website, or B: read the assembly directly. But here I choose C. I bet there's no bullet in the shooter's gun.

cm = 'cbtcqLUBChERV[[Nh@_X^D]X_YPV[CJ'
flag = ''
for i in range(len(cm)):
	flag += chr(ord(cm[i]) ^ 0x37)


At first, I thought it was just to plug the flag directly and turn the numbers into characters, but it was not right after verification

Then I look at the main function carefully, and find that there is a process of MD5 encryption for the input, so it is necessary to solve MD5 directly online


It's a c code, which reverses the result

First is_ok must be 1, then the following two strings must be equal

    int is_ok = 1;
    for (i = 0; i < FLAG_LEN; i++) {
        if (generated_string[i] != just_a_string[i])  //Must be equal
            return 0;
    return 1;

To be equal, result must be 0

    for (i = 0; i < FLAG_LEN; i++) {
        pthread_join(*(thread+i), &result);
        generated_string[i] = *(char *)result + just_a_string[i];  //ressul must be 0

Then the checking function returns to 0

    char *arguments[20];
    for (i = 0; i < FLAG_LEN; i++) {
        arguments[i] = (char *)malloc(3*sizeof(char));
        arguments[i][0] = first_letter;    //Generated random number
        arguments[i][1] = differences[i];  //Given string
        arguments[i][2] = user_string[i];  //Your input

        pthread_create((pthread_t*)(thread+i), NULL, checking, arguments[i]);

Then * * (argument[0]+argument[1]) and argument[2] must be the same**

void * checking(void *arg) {
    char *result = malloc(sizeof(char));
    char *argument = (char *)arg;
    *result = (argument[0]+argument[1]) ^ argument[2];  //Same, exclusive or is 0
    return result;

Then we know that arg[0] is the generated random number, ranging from 97 to 97 + 26, and start blasting

a = [0, 9, -9, -1, 13, -13, -4, -11, -9, -1, -7, 6, -13, 13, 3, 9, -13, -11, 6, -7]
for i in range(97,123):
	flag = ''
	for j in range(len(a)):
		flag += chr(i + a[j])


There are three files in the folder. exe runs and it is found to flash back. kali runs as follows

[the external link image transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-ihkhqwmn-1593054216969)( ]

I don't know what it is. IDA can see the output logic corresponding to the figure above, but it doesn't seem to be useful

[the external link image transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-sewwwyat-1593054216970)( ]

OK, I have no idea. It's time to shift+f12

We found a black mysterious galaxy that existed but didn't show its output, and then cross referenced it all the way

Good guys, they are all assignment operations. We recommend thorough investigation, where we record the addresses at the end and then go to OD to debug them.

Here's an extra point (because this problem bothered me at the beginning). How to quickly check the address? Just enter text view as shown in the figure below

Select, right-click - follow - memory address in data window, and then run

[the external link image transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-ttexd9oa-1593054216974)( ]

The string can be submitted directly.

In fact, it's quite a simple question, but at the beginning, I didn't expect that a lot of random analysis was as fierce as a tiger, and then I saw the solution of the question before I understood that I didn't talk about it.


Directly into the winmain function, there are some nonsense can not understand the problem is not big, direct analysis of the main contradictions on OK.

Just make it successful. Pay attention to the definition of V11.


At the beginning of this problem, I mistakenly understood that atoi and itoa had led to a lot of tangled time. I suggest reading the function description carefully. Then notice that the definition given by this string is char

Main precautions are as follows:


General process: the program makes a series of judgments on the input, and then compares the input with the given string after the input is out of order. Some if statements that are not useful for problem solving can be skipped selectively. See the note for details

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
  __pid_t v3; // eax
  size_t v4; // rax
  ssize_t v5; // rbx
  bool v6; // al
  bool bCheckPtrace; // [rsp+13h] [rbp-1BDh]
  ssize_t numRead; // [rsp+18h] [rbp-1B8h]
  ssize_t numReada; // [rsp+18h] [rbp-1B8h]
  char bufWrite[200]; // [rsp+20h] [rbp-1B0h]
  char bufParentRead[200]; // [rsp+F0h] [rbp-E0h]
  unsigned __int64 v12; // [rsp+1B8h] [rbp-18h]

  v12 = __readfsqword(0x28u);
  bCheckPtrace = detectDebugging();
  if ( pipe(pParentWrite) == -1 )
  if ( pipe(pParentRead) == -1 )
  v3 = fork();
  if ( v3 != -1 )
    if ( v3 )
      while ( 1 )
        printf("Input key : ");
        memset(bufWrite, 0, 0xC8uLL);
        gets(bufWrite);                         // input
        v4 = strlen(bufWrite);
        v5 = write(pParentWrite[1], bufWrite, v4);// Write bufwrite to pparentwrite
        if ( v5 != strlen(bufWrite) )
          printf("parent - partial/failed write");// v5==bufwrite length means no error write
          memset(bufParentRead, 0, 0xC8uLL);
          numReada = read(pParentRead[0], bufParentRead, 0xC8uLL);// Read data with length of 0xc8 from pParentRead to bufParentRead
          v6 = bCheckPtrace || checkDebuggerProcessRunning();
          if ( v6 )
            puts("Wrong !!!\n");                // Decompile
          else if ( !checkStringIsNumber(bufParentRead) )
            puts("Wrong !!!\n");                
            if ( atoi(bufParentRead) )          // Non empty & can be converted to plastic
              if ( close(pParentWrite[1]) == -1 )
            puts("Wrong !!!\n");
        while ( numReada == -1 );
    while ( 1 )
      memset(bufParentRead, 0, 0xC8uLL);
      numRead = read(pParentWrite[0], bufParentRead, 0xC8uLL);
      if ( numRead == -1 )
      if ( numRead )
        if ( childCheckDebugResult() )
        else if ( bufParentRead[0] == '{' )
          if ( strlen(bufParentRead) == 42 )
            if ( !strncmp(&bufParentRead[1], "53fc275d81", 0xAuLL) )
              if ( bufParentRead[strlen(bufParentRead) - 1] == '}' )
                if ( !strncmp(&bufParentRead[31], "4938ae4efd", 0xAuLL) )
                  if ( !confuseKey(bufParentRead, 42) )// Key disorder function
                  else if ( !strncmp(bufParentRead, "{daf29f59034938ae4efd53fc275d81053ed5be8c}", 0x2AuLL) )

Key key obfuscation function:

  strncpy(szPart1, szKey + 1, 0xAuLL);          // Except for '{' and '}' in the first place, the rest are in groups of 10 bits
  strncpy(szPart2, szKey + 11, 0xAuLL);
  strncpy(szPart3, szKey + 21, 0xAuLL);
  strncpy(szPart4, szKey + 31, 0xAuLL);
  memset(szKey, 0, 0x2AuLL);
  *szKey = '{';                                 // Plus the head
  strcat(szKey, szPart3);                       // The order is 3, 4, 1, 2. Just restore
  strcat(szKey, szPart4);
  strcat(szKey, szPart1);
  strcat(szKey, szPart2);
  szKey[41] = '}';                              // Plus the tail


Look directly at the procedure

  printf("Gimme: ", argv, envp);
  __isoc99_scanf((__int64)"%d", (__int64)&v4);  // Give an input, int
  not_the_flag(v4);                             // Critical judgment


  if ( a1 == 42 )
    puts("Cipher from Bill \nSubmit without any tags\n#kdudpeh");// Pay attention to the format
    puts("YOUSUCK");                            // You climb

If the input value is 42, the password from bill will be output, and no label is required, so the password is kdudpeh, and an error will be found in the submission, which shows the importance of reading questions. The password from sha1, OK, sha1 encryption

Program run test:

[external link image transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-hgSDfAfr-1593054216979)(C:\Users\yi\AppData\Roaming\Typora\typora-user-images\image-20200607181210187.png))

Encryption script (online encryption is also available):

import hashlib


Let's start with the general idea of the topic. First, an if judgment is made, and * * "Access granted" * * is output successfully. At the same time, the functions below the puts are executed.

Enter sub_8048414 function, the program is still very simple, directly tear by hand, get a2: isengard

Continue to analyze and enter sub_8048538, the parameters of the function use the a2 we just got above. In general, this is an output process. Guess that the output is a flag, and that is a pair of Unks_ The data in 8048760 is extracted, and then a simple XOR is performed

Data extraction: select data in IDA and press shift+e to extract data. There are useless parts in the extracted data, which need to be extracted again. For example, if you take the first one out of four bytes of int, it is OK. The script is as follows (because python is not good at learning, it uses c + +)

using namespace std;
int main()
    int a[] = {  0x0F, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x00, 
  0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 
  0x12, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x09, 0x00, 
  0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 
  0x0D, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 
  0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 
  0x37, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x1E, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 
  0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1C, 0x00, 
  0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 
  0x07, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x02, 0x00, 
  0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 
  0x41, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 
  0x00, 0x00};
  int j = 0;
  int x = sizeof(a)/16;
  int b[x];
  cout<<"length is:"<<x<<endl;
  for(int i =0;i<sizeof(a)/4;i++)
    if (i%4==0)
        b[j++] = a[i];
  for(int c = 0;c<sizeof(b)/4;c++){
  return 0;

Extract the data and start writing the flag script

a = [105,115,101,110,103,97,114,100]
b = [15,31,4,9,28,18,66,9,12,68,13,7,9,6,45,55,89,30,0,89,15,8,28,35,54,7,85,2,12,8,65,10,20]
flag = ''
for i in range(len(b)):
  flag += chr(b[i] ^ a[i % 8])

Or the simpler way is, since the judgment is successful, the output will be output, and we already know the input, then run it directly in kali


It's hard to say that it's reverse, but I learned a little about the xxd instruction

First, use the execinfo or file command to view the file type: ASCII text, with CRLF line terminators

Drag into sublime to check

00400080  68 66 6C 00 00 48 BF 01  00 00 00 00 00 00 00 48
00400090  8D 34 24 48 BA 02 00 00  00 00 00 00 00 48 B8 01
004000A0  00 00 00 00 00 00 00 0F  05 68 61 67 00 00 48 BF
004000B0  01 00 00 00 00 00 00 00  48 8D 34 24 48 BA 02 00
004000C0  00 00 00 00 00 00 48 B8  01 00 00 00 00 00 00 00
004000D0  0F 05 68 7B 70 00 00 48  BF 01 00 00 00 00 00 00
004000E0  00 48 8D 34 24 48 BA 02  00 00 00 00 00 00 00 48
004000F0  B8 01 00 00 00 00 00 00  00 0F 05 68 6F 70 00 00
00400100  48 BF 01 00 00 00 00 00  00 00 48 8D 34 24 48 BA
00400110  02 00 00 00 00 00 00 00  48 B8 01 00 00 00 00 00
00400120  00 00 0F 05 68 70 6F 00  00 48 BF 01 00 00 00 00
00400130  00 00 00 48 8D 34 24 48  BA 02 00 00 00 00 00 00
00400140  00 48 B8 01 00 00 00 00  00 00 00 0F 05 68 70 72
00400150  00 00 48 BF 01 00 00 00  00 00 00 00 48 8D 34 24
00400160  48 BA 02 00 00 00 00 00  00 00 48 B8 01 00 00 00
00400170  00 00 00 00 0F 05 68 65  74 00 00 48 BF 01 00 00
00400180  00 00 00 00 00 48 8D 34  24 48 BA 02 00 00 00 00
00400190  00 00 00 48 B8 01 00 00  00 00 00 00 00 0F 05 68
004001A0  7D 0A 00 00 48 BF 01 00  00 00 00 00 00 00 48 8D
004001B0  34 24 48 BA 02 00 00 00  00 00 00 00 48 B8 01 00
004001C0  00 00 00 00 00 00 0F 05  48 31 FF 48 B8 3C 00 00
004001D0  00 00 00 00 00 0F 05   

Here you can write a script to convert the hexadecimal code to ASCII code. Here you will learn how to convert with the xxd instruction

I haven't found a good article about the content of the xxd instruction. Here are two articles that can barely be written:



It can be analyzed directly here. The rule is still obvious, or you can select printable characters first if you feel uncomfortable

a = "@�hflH�H@��4$H�H�@�hagH�@�H�4$H�@�H�@�h{pH�@�H�4$H�H@��hop@H�H�4$H�@H�@ hpoH�@0H�4$H�@@H�hpr@PH�H�4$@`H�H�@phetH�@�H�4$H�@�H�h@�}H�H�@�4$H�H�@�H1�H�<@� "
flag = ''
for i in range(len(a)):
  if(ord(a[i]) >= 32 and ord(a[i]) <= 125):
    flag += a[i]

Get string:

@hflHH@4$HH@hagH@H4$H@H@h{pH@H4$HH@hop@HH4$H@H@ hpoH@0H4$H@@Hhpr@PHH4$@`HH@phetH@H4$H@Hh@}HH@4$HH@H1H<@ 

It's obvious that we need the characters after H and before h (sometimes @)

Get the flag:


Then I handed it in many times and found it was wrong. Just remove the flag {}

Here is an additional instruction second solution, link


Cross reference string pass! Find the key function. The function logic is to transform the input character according to the ascii code value. The transformed result is the string abcd Index of XYZ.


a = 'abcdefghiABCDEFGHIJKLMNjklmn0123456789opqrstuvwxyzOPQRSTUVWXYZ'
b = 'KanXueCTF2019JustForhappy'
f = []
for i in range(len(b)):
    for j in range(len(a)):
        if(a[j] == b[i]):
for i in range(len(f)):
    if(f[i]>=10 and f[i] <= 35):
        f[i] += 87
    elif(f[i]>=0 and f[i] <= 9): 
        f[i] += 48
    elif(f[i]>=36 and f[i] <= 61):  
        f[i] += 29
flag = ''
for i in range(len(f)):
    flag += chr(f[i])

When writing the script, I made a mistake. For the first time, I used three if statements instead of elif. As a result, after the first if judgment, the modified value may meet the remaining if judgment conditions, resulting in many successful judgments. I didn't find out at that time. Thank you brother ld1ng Correction of.


When I wake up and open it, there are many things on the homepage that I didn't want to write, obsessive-compulsive disorder, I can't help it

The logic is simple. It's directly scripted

key = 0x12
flag = ''
cmpa = [0x69, 0x7A, 0x77, 0x68, 0x72, 0x6F, 0x7A, 0x22, 0x22, 0x77, 
0x22, 0x76, 0x2E, 0x4B, 0x22, 0x2E, 0x4E, 0x69]
for i in range(0,6):
    x = chr((cmpa[3 * i] ^ key) - 6)       #Pay attention to the priority of exclusive or
    y = chr((cmpa[3 * i + 1] ^ key) + 6)
    z = chr((cmpa[3 * i + 2] ^ key) ^ 6) 
    flag += x
    flag += y
    flag += z

Notice the priority of XOR here. I didn't put parentheses in the beginning, and the result was wrong. Then I realized that the priority of XOR seemed to be lower than that of minus and plus.


Thank you two Shifu first ld1ng and iyzyi It's nice to have you to help me with this question ☺️.

What I don't understand about this question is its unique parameter representation, which is unheard of (mainly ignorant).

First of all, this problem has a shell, but upx-d can be detached directly, but the program will flash back after the shelling. The reason is that the program has ASLR enabled, but the absolute address is used, so you can turn off ASLR. Here I also use for reference the blog of the online tycoon, link:

as well as

We go directly to the key function. To understand the program, we must understand * * * v1 = byte_402FF8[(char)v1[(_DWORD)v4]] * * this code, it is worth noting that no matter v1,v4 or a1 are all pointer forms, for v4 = (a1 - v1), the formula can be rewritten as (v1 + v4) = a1, while * (v1[v4]) can be understood as * (v1 + v4), so * (v1 + v4) points to a1, which completes the increase of a1 with the increase of V1 in the while loop. The input character obtained by increment is used as index, and in byte_402ff8 look-up table conversion, the converted value is stored in V1.

unsigned int __cdecl sub_401000(const char *a1)
  _BYTE *v1; // ecx
  unsigned int v2; // edi
  unsigned int result; // eax
  const char *v4; // ebx

  v2 = 0;
  result = strlen(a1);
  if ( result )
    v4 = (const char *)(a1 - v1);               // Rewrite as: v1 + v4 = a1 
                                                // As v1 increases, the whole input is traversed
      *v1 = byte_402FF8[(char)v1[(_DWORD)v4]];  // *(v1[v4]) is equivalent to * (v1 + v4)
                                                // Index the input character in byte_402ff8 look up table conversion
      result = strlen(a1);
    while ( v2 < result );
  return result;

And then for byte_402ff8, but click it to find the following:

At first, I was a little confused because of byte_402ff8 is followed by a bunch of things that you don't know, but you can find that the address hasn't changed, it should be some statements, and then you can try to directly select them for data extraction, as shown in the figure.

Then there is another way of thinking on the Internet. After 32, the starting address of ASCII visible characters is 0x00402ff8, plus 32 happens to be 0x403018, so you can see the data directly.

In this way, the input conversion is completed. The next step is string comparison. Note that when calling the function, the parameter passed in is only v6, but when comparing it with v4, the program can't see the clue. Let's look at the assembly. Before calling the function, the address of v4 is sent as ecx, as shown below:

Then enter the called function and find that v1 is exactly ecx, and the converted value is saved in v1, and v1 is v4, so the converted value is saved in v4, as shown in the following figure:

The rest of this is simple. Judge v4 and the given string, and reverse it to find the string DDCTF{reverseME} in byte_402ff8. Convert the position index to character, that is, input. The script is as follows:

a = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4E, 0xE6, 
  0x40, 0xBB, 0xB1, 0x19, 0xBF, 0x44, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 
  0x00, 0x00, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78, 0x77, 
  0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70, 0x6F, 0x6E, 0x6D, 
  0x6C, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 
  0x62, 0x61, 0x60, 0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 
  0x58, 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4F, 
  0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 
  0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 
  0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 
  0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 
  0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x00, 0x00, 0x00, 
  0x00, 0x00]
b = 'DDCTF{reverseME}'
flag = ''
for i in range(len(b)):
    flag += chr(a[ord(b[i])])

Tags: ascii SHA1 REST Python

Posted on Thu, 25 Jun 2020 00:18:12 -0400 by knnakai