➜ ~

Playing Hacks and Stuffs!


Project maintained by h4ckyou Hosted on GitHub Pages — Theme by mattgraham

ABCCTF Final 2023 Writeup

Hi everyone, in this writeup I’ll give just the solution of the challenges which had one solve and was blooded by me

Reveal (Binary Exploitation)

image

We are given a netcat instance and a zip file

After downloading the zip file and unzipping it I got this image

So it has a binary and it’s libc file

Since this is given I patched the binary to use that libc because that’s what going to be running on the remote instance

I patched it using pwninit

Time to start the real deal here :P

Checking the file type and protections enabled on the binary shows this image

We’re working with a x64 binary which is dynamically linked and not stripped

All protections are enabled on this binary 💀

I decided to run it to get an idea of what it does image

Cool it seems to receive our input twice

Inorder to find the vulnerability we need to decompile the binary

At first when I used Ghidra and viewed the main function I got this image


undefined8 main(void)

{
  undefined buffer [56];
  long canary;
  
  setup();
  canary = 0x13371337132763b7;
  write(1,
        "Tell me something thrilling and i\'ll share my dirty little secrets, nothing porn related t hough xD: "
        ,100);
  read(0,buffer,0x40);
  printf("You: %s",buffer);
  write(1,"Please, do tell me more, i\'m dying to find out: ",0x30);
  read(0,buffer,100);
  if (canary != 0x13371337132763b7) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}

From this there are two vulnerability:

With that said what can we do with this?

Well normally even if we can leak the canary we are still limited cause PIE is enabled so ROP isn’t an option

It almost seemed impossible until I looked at the assembly decompilation in ghidra and saw this image

   0x00000000000011e6 <+4>:     push   rbp
   0x00000000000011e7 <+5>:     mov    rbp,rsp
   0x00000000000011ea <+8>:     sub    rsp,0x40
   0x00000000000011ee <+12>:    mov    eax,0x0
   0x00000000000011f3 <+17>:    call   0x11b9 <setup>
   0x00000000000011f8 <+22>:    mov    rax,QWORD PTR [rip+0x2de1]        # 0x3fe0
   0x00000000000011ff <+29>:    mov    rdx,rax
   0x0000000000001202 <+32>:    movabs rax,0x1337133713371337
   0x000000000000120c <+42>:    xor    rax,rdx
   0x000000000000120f <+45>:    mov    QWORD PTR [rbp-0x8],rax

So basically it will move the value of printf@libc to the rax register then mov rax to rdx i.e the value to rdx, then it moves 0x1337133713371337 to the rax and xors rax and rdx the value is then move to the rax register and is used as the canary value

   0x00000000000012a0 <+190>:   mov    rax,QWORD PTR [rip+0x2d39]        # 0x3fe0
   0x00000000000012a7 <+197>:   mov    rdx,rax
   0x00000000000012aa <+200>:   movabs rax,0x1337133713371337
   0x00000000000012b4 <+210>:   xor    rax,rdx
   0x00000000000012b7 <+213>:   cmp    QWORD PTR [rbp-0x8],rax
   0x00000000000012bb <+217>:   je     0x12c7 <main+229>
   0x00000000000012bd <+219>:   mov    eax,0x0
   0x00000000000012c2 <+224>:   call   0x10a0 <__stack_chk_fail@plt>
   0x00000000000012c7 <+229>:   mov    eax,0x0
   0x00000000000012cc <+234>:   leave
   0x00000000000012cd <+235>:   ret

But if you use IDA for decompilation it actually does a pretty good job decompiling it xD image

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf[56]; // [rsp+0h] [rbp-40h] BYREF
  unsigned __int64 v5; // [rsp+38h] [rbp-8h]

  setup(argc, argv, envp);
  v5 = (unsigned __int64)&printf ^ 0x1337133713371337LL;
  write(
    1,
    "Tell me something thrilling and i'll share my dirty little secrets, nothing porn related though xD: ",
    0x64uLL);
  read(0, buf, 64uLL);
  printf("You: %s", buf);
  write(1, "Please, do tell me more, i'm dying to find out: ", 0x30uLL);
  read(0, buf, 100uLL);
  return 0;
}

So…. at this point we know that it’s solvable because we can leak the canary therefore getting the printf@libc value because the value was xored with 0x1337133713371337 and from the property of xor we can retrieve the other value by just xoring canary with the hardcoded value 0x1337133713371337

What next?

Well the point we have a libc leak means we can just calculate the libc base address and therefore using the second buffer overflow we can just rop or jump to a one_gadget

I tried ropping but I had stack allignment issue and there wasn’t a ret; instruction in the libc file so I decided to use a one_gadget

Let’s get the one_gadget addresses image


➜  revealZ one_gadget libc.so.6 
0x50a47 posix_spawn(rsp+0x1c, "/bin/sh", 0, rbp, rsp+0x60, environ)
constraints:
  rsp & 0xf == 0
  rcx == NULL
  rbp == NULL || (u16)[rbp] == NULL

0xebc81 execve("/bin/sh", r10, [rbp-0x70])
constraints:
  address rbp-0x78 is writable
  [r10] == NULL || r10 == NULL
  [[rbp-0x70]] == NULL || [rbp-0x70] == NULL

0xebc85 execve("/bin/sh", r10, rdx)
constraints:
  address rbp-0x78 is writable
  [r10] == NULL || r10 == NULL
  [rdx] == NULL || rdx == NULL

0xebc88 execve("/bin/sh", rsi, rdx)
constraints:
  address rbp-0x78 is writable
  [rsi] == NULL || rsi == NULL
  [rdx] == NULL || rdx == NULL
➜  revealZ

When using one gadget we need to make sure the constraint are ok before using it else it won’t work

I used the first address and I need to make sure rbp == 0

The other register seems to work without setting it 0 for some reason (I did take a look at the register when the program was returning and it wasn’t entirely null)

To get a gadget to use preferably a pop rbp gadget I used ropper image

ropper --file libc.so.6 --search "pop rbp; ret;"

With that it’s all set 🙂

So our goal is to first leak canary, calculate libc base then jump to one_gadget

For the second stage of our exploit we need to first overwrite the canary value to its original value then overwrite saved rbp with some junk value of 8 bytes then finally our rop gadget with one_gadget

Here’s my exploit: script

Running it works locally image

Doing the same remtotely works then we can grab our flag image

Flag: abcctf{see_the_unseen_and_bring_the_flag_to_life}

Simple Calculator (Web Exploitation)

image

Going over the web page shows this calculator sort of interface image

Looking at the page source just shows a client side javascript being used by the calculator that helps evalutes the user input image

Since it’s client side I didn’t really bother checking it even though it uses eval but this javascript not nodejs also client side not serverside besides i don’t think it’s possible to execute system command with javascript

With that said I decided to look at the report a bug function this webapp provides image

I tried using a random value but I noticed it doesn’t seem to do anything image

At this point it became hard not because the challenge is hard itself but the text there was really misleading 😂

After spamming like various xss payload or anything that can make it do a callback to the webhook site, it didn’t work

I fuzzed with any extension I could think of and various wordlist but still nothing!

So I left this challenge to work on other things

But eventually after some hours the creator @Muzec gave a hint saying “BLIND”

Hmmmmmmm blind what exactly?

I decided to try command injection to invoke a sleep call

Doing that worked! image

So let’s get a reverse shell shall we?

I hosted a http server which had a file rev.sh containing a reverse shell then did this image image

The flag was in the environment variable

Flag: abcctf{51MP13_r3P0r7_607_Y0U_7H3_F146}

This is all I believe I don’t need to make a writeup on the remaining ones I solvef cause it’s pretty much solvable by anyone just strings & grep

Welp that’s all I did 😛

After the end of the ctf I came out first 🙏 image