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.
Guess-the-Number
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]) print(flag)
EasyRE
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 .text:00401111 loc_401111: ; CODE XREF: sub_401080+6F↑j .text:00401111 xor edx, edx .text:00401113 .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 .text:00401132
[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)( https://i.loli.net/2020/06/03/huBINj1t6pECA8m.png ]
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) print(flag[::-1])
Shuffle
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]) print(flag)
re-for-50-plz-50
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) print(flag)
dmd-50
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
parallel-comparator-200
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 free(result); free(arguments[i]); }
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]) print(flag)
secret-galaxy-300
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)( https://i.loli.net/2020/06/01/Utxuy2CkMQPe4X7.png ]
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)( https://i.loli.net/2020/06/01/MBA7rUWn8GE3Cja.png ]
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)( https://i.loli.net/2020/06/01/apnPxU5dftAQ2wJ.png ]
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.
srm-50
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.
Mysterious
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:
re1-100
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 ) exit(1); if ( pipe(pParentRead) == -1 ) exit(1); v3 = fork(); if ( v3 != -1 ) { if ( v3 ) { close(pParentWrite[0]); close(pParentRead[1]); 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 do { 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"); } else { if ( atoi(bufParentRead) ) // Non empty & can be converted to plastic { puts("True"); if ( close(pParentWrite[1]) == -1 ) exit(1); exit(0); } puts("Wrong !!!\n"); } } while ( numReada == -1 ); } } close(pParentWrite[1]); close(pParentRead[0]); while ( 1 ) { memset(bufParentRead, 0, 0xC8uLL); numRead = read(pParentWrite[0], bufParentRead, 0xC8uLL); if ( numRead == -1 ) break; if ( numRead ) { if ( childCheckDebugResult() ) { responseFalse(); } 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 { responseFalse(); } else if ( !strncmp(bufParentRead, "", 0x2AuLL) ) { responseTrue(); } else { responseFalse(); } } else { responseFalse(); } } else { responseFalse(); } } else { responseFalse(); } } else { responseFalse(); } } else { responseFalse(); } } } exit(1); } exit(1); }
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
answer_to_everything
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
not_the_flag
if ( a1 == 42 ) puts("Cipher from Bill \nSubmit without any tags\n#kdudpeh");// Pay attention to the format else 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 a='kdudpeh' b=hashlib.sha1(a.encode('utf-8')) print(b.hexdigest())
elrond32
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 + +)
#include<iostream> #include<cstring> 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++){ cout<<b[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]) print(flag)
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
tt3441810
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:
1.https://www.sohu.com/a/341144249_610671
2.https://blog.csdn.net/xingyyn78/article/details/79438853
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�@�hH�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] print(flag)
Get string:
@hflHH@4$HH@hagH@H4$H@H@hHH@4$HH@H1H<@
It's obvious that we need the characters after H and before h (sometimes @)
Get the flag:
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 https://github.com/ctfs/write-ups-2014/tree/master/tinyctf-2014/tt3441810
fugitive
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.
script:
a = 'abcdefghiABCDEFGHIJKLMNjklmn0123456789opqrstuvwxyzOPQRSTUVWXYZ' b = 'KanXueCTF2019JustForhappy' print(len(b)) print(len(a)) f = [] for i in range(len(b)): for j in range(len(a)): if(a[j] == b[i]): f.append(j) 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]) print(flag)
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.
666
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 print(flag)
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.
Windows_Reverse1
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:
https://blog.csdn.net/qq_43547885/article/details/104412656
as well as http://blog.eonew.cn/archives/749
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 do { *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 ++v2; ++v1; 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 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' flag = '' for i in range(len(b)): flag += chr(a[ord(b[i])]) print(flag)