Category: Misc

Points: 500

Description:

During the great battle of IRSEC 2015 we lost a great man, Phil. The blue teams fought effortlessly to keep him save but sadly they did not stand a chance against their attackers. Since losing him in that great battle our team has been searching tirelessly for Phil. Recently, we received credible intelligence that this team recruits new members by putting them through a series of challenges. The challenge starts with this file. It is your job to join their organization, and find Phil. Bring him home safe.

Download Link: https://drive.google.com/file/d/0Bw7N3lAmY5PCTkFXQzQ2YmpoTlE/view?usp=sharing

Note

b0tchsec was the second player to solve this challenge. Big thanks to whatbatman and captainevilwaffl for the awesome challenge.

STEP 1

a quick strings file.png shows us there are other filenames in our image. Let’s run unzip file.png and see what we’ve got.

STEP 2

The series of smaller png files appear to be pieces of a puzzle that need to be put together. This can be accomplished in gimp by loading all the images as layers.

The image, once put back together from the smaller images, takes us to termbin.com/vf6t

You have proved yourself to be at least some what formidable. Congratulations. Now that you have proven your technical skills, you need to prove your   loyalty.
There is a new company that is creating a rather large buzz, EnergyCorp. They are run by the former creator and CEO of Xanadu, LordReverend Kane. 
We hear that there is a secret to their power, hidden behind their protected website. We need you to gain access to their secrets, and return them to us.
The website can be found here:
http://ec2-52-71-70-98.compute-1.amazonaws.com:6100
Don't get caught.

STEP 3

The homepage tells us to use http://idcreator.com to create our own ID with a format we learned during orientation. Too bad we didn’t go to orientation. But its good to know that we can create an ID.

Looking around on the company site, we see the facebook page, and it has a post about their newest employee Jennifer Jones. If we check out Jennifer’s facebook page, we see she’s friends with LordReverend Kane, but LordReverend Kane keeps his shit on lock.

If we look at the EnergyCorp posts page, we see that a guy named Ben Franklin, with a convenient stock photo, started working at EnergyCorp just before the challenge started. Let’s inspect him too.

To login to the site we need to upload a photo of our ID. I’m sure if we look hard enough, we can find that ID on one of the facebook profiles. OSINT is a real threat. If we take a look around Jennifer’s facebook again, sure enough she uploaded a photo of her badge. Let’s use that and see if we can login.

We get an error message telling us User already logged in. Looks like it’s time to bust out some photoshop.

Given the badge format, I most expect the backend to be scanning the QR code and ignoring the rest of it. Let’s try to generate a new QR vcard code using LordReverend Kane’s information, after all, he’s the CEO.

No such luck, he’s also logged in. Thankfully we also noticed that Ben Franklin is a new employee. Since he’s so new, maybe he hasn’t logged into the system yet. Let’s use his facebook page to generate a QR Code. Let’s also rip his image and include it in the badge.

Ben Franklin
Chief Imagination Engineer
Energy Corp
(I used my personal email in the event that EnergyCorp website looks. Used fake phone number)

Once we’ve generated the QR code, line it up to fit snugly over the existing QR code on the badge, save that as a new image and try to upload it.

Success, we’ve made it to the “Welcome” page for employees.

STEP 4

Nothing too interesting in the vault, just a cute puppy and a cute turtle. Let’s take a look in fiddler and see what’s happening.

HTTP/1.0 404 NOT FOUND
Content-Type: QW9HQU5VWWNTUS9vQWs3a3BNTDRqYnZhQk1kWEtVc2VMZEEvcmZxWENUSkVQTXBFTTAwVmtONFlYVmlsQ0JpdA==
Content-Length: MVZNSjJHZ04wcHRLSklHdjZNMGMyT2hkdkFSakFpRWltcVR6YkdINGlMSk90ekh3c2pZL0lJemQwUUlEQVFBQg==
Accept: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQ==
Content-Security-Policy: TUlJQ1hBSUJBQUtCZ1FDWHRVUXR5WUdHdldidlBsUlRRUWEwRmNIWkY3QUNTOVhqYWtscDd4dWtsMkcvL0luLw==
Server: NkVEcFYxamk1Yk5oaXF0SmdYUUk0UGljZ3huQVdpTjFBVVhhOFVSc0QvNlVhQ3RhbUsyWE9pM1VsN3BaMS9oYQ==
Date: bzJVMHZUMU9hQWZJaGYycnYxWm4rU0NYVEx3OC9TUDlBMitRdTRmcU1zWGVDaUx1eEVRdzR0cUsrbnYwR2RJMA==
Pragma: aDJramlpcHpJWEQ2M3JFNUhiZXQwK2VORkdzbjBIdTFtU1IyQ3hHcjFCQ2pWVmtDUVFEdmVVMGxsdHVqaVBDMw==
Expires: eElvOEJjem9zSCt5Vi9INE1iZFBNUWFJcHUwZHFQN1VxMi84UHR3Q3BXVFJQS3JpT2dlUlF4ZU1TTjk4SnVWTw==
Cache-Control: TVpwb1BCSGZBa0VBb2kxd1NSYU1NMFM5ZWhCZ1dsRm85ZUxjaWY1a21VRmtRYnBQL1dBVzF4SWtYVW5nbTZibw==
Warning: VGpVenRZN3VhckpoVEFYeGtNZERwY0FaTlo5YXNxdm1Ud0pCQUpmYmpTOTBEYzRUYmNxckNKbnRkN1pyRGw4eQ==
Downlink: NDg5bS8zNXBjV0pBc0lhcGZ3ZXZ1M0R6RDZOaDdKKys0QUpibUNibXE4MGEvUldHdU15d0tlRkZqbk1DUUNOeA==
Save-Data: a00rNGFNMnZvVVZ6SE12QWJSTUlFTERyOHlwM1d5VHVSaHNYREFiWEJUR0tPdGRwdysyTHZSQlorNHRBRHZtaA==
Width: ZHVqd1U3MSszVU9WM3ltYlhnc0NRRzZ6Y3k1bGtlWEYrcnhaNWFSd3d4cGlBSnAvVEFsVmo4djZIWmE4SXovTQ==
ETag: cEhtM0k2RkFEOXhjWmhTMlg4RVRHdHh1cklxWVVBWndxOHVWRWE4T2g3QQ==
Keep-Alive: LS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0=
Age: YWNjZXB0LCBjb250ZW50LXNlY3VyaXR5LXBvbGljeSwgc2VydmVyLCBjb250ZW50LWxlbmd0aCwgY29udGVudC10eXBlLCBkYXRlLCBwcmFnbWEsIGV4cGlyZXMsIGNhY2hlLWNvbnRyb2wsIHdhcm5pbmcsIGRvd25saW5rLCBzYXZlLWRhdGEsIHdpZHRoLCBldGFnLCBrZWVwLWFsaXZl
Integrity Checksum: M9hxHUdd8mUdxaz1nPSy6Tol7h8OYcS2SBficdhrvObfmi1DSkXOmi8/aGs5POtvODpi+8FcOeqmUsqOWOcGTl5fy3zJtSIfr9CkywaYWtVaoJb+8R3t+G32dgTEHpgI4y69kJabOruAwbldqHmCSRhSLr0mTFGxmd+HwBNgj3s=

This looks like base64 garbage. Let’s decode it all.

AoGANUYcSQ/oAk7kpML4jbvaBMdXKUseLdA/rfqXCTJEPMpEM00VkN4YXVilCBit
1VMJ2GgN0ptKJIGv6M0c2OhdvARjAiEimqTzbGH4iLJOtzHwsjY/IIzd0QIDAQAB
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCXtUQtyYGGvWbvPlRTQQa0FcHZF7ACS9Xjaklp7xukl2G//In/
6EDpV1ji5bNhiqtJgXQI4PicgxnAWiN1AUXa8URsD/6UaCtamK2XOi3Ul7pZ1/ha
o2U0vT1OaAfIhf2rv1Zn+SCXTLw8/SP9A2+Qu4fqMsXeCiLuxEQw4tqK+nv0GdI0
h2kjiipzIXD63rE5Hbet0+eNFGsn0Hu1mSR2CxGr1BCjVVkCQQDveU0lltujiPC3
xIo8BczosH+yV/H4MbdPMQaIpu0dqP7Uq2/8PtwCpWTRPKriOgeRQxeMSN98JuVO
MZpoPBHfAkEAoi1wSRaMM0S9ehBgWlFo9eLcif5kmUFkQbpP/WAW1xIkXUngm6bo
TjUztY7uarJhTAXxkMdDpcAZNZ9asqvmTwJBAJfbjS90Dc4TbcqrCJntd7ZrDl8y
489m/35pcWJAsIapfwevu3DzD6Nh7J++4AJbmCbmq80a/RWGuMywKeFFjnMCQCNx
kM+4aM2voUVzHMvAbRMIELDr8yp3WyTuRhsXDAbXBTGKOtdpw+2LvRBZ+4tADvmh
dujwU71+3UOV3ymbXgsCQG6zcy5lkeXF+rxZ5aRwwxpiAJp/TAlVj8v6HZa8Iz/M
pHm3I6FAD9xcZhS2X8ETGtxurIqYUAZwq8uVEa8Oh7A
-----END RSA PRIVATE KEY-----
accept, content-security-policy, server, content-length, content-type, date, pragma, expires, cache-control, warning, downlink, save-data, width, etag, keep-alive
[ENCRYPTED STRING HERE, CONTAINS NON PRINTABLES]

The bit after —–END RSA PRIVATE KEY—– looks like a specific order. Let’s rearrange the key to match.

-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCXtUQtyYGGvWbvPlRTQQa0FcHZF7ACS9Xjaklp7xukl2G//In/
6EDpV1ji5bNhiqtJgXQI4PicgxnAWiN1AUXa8URsD/6UaCtamK2XOi3Ul7pZ1/ha
1VMJ2GgN0ptKJIGv6M0c2OhdvARjAiEimqTzbGH4iLJOtzHwsjY/IIzd0QIDAQAB
AoGANUYcSQ/oAk7kpML4jbvaBMdXKUseLdA/rfqXCTJEPMpEM00VkN4YXVilCBit
o2U0vT1OaAfIhf2rv1Zn+SCXTLw8/SP9A2+Qu4fqMsXeCiLuxEQw4tqK+nv0GdI0
h2kjiipzIXD63rE5Hbet0+eNFGsn0Hu1mSR2CxGr1BCjVVkCQQDveU0lltujiPC3
xIo8BczosH+yV/H4MbdPMQaIpu0dqP7Uq2/8PtwCpWTRPKriOgeRQxeMSN98JuVO
MZpoPBHfAkEAoi1wSRaMM0S9ehBgWlFo9eLcif5kmUFkQbpP/WAW1xIkXUngm6bo
TjUztY7uarJhTAXxkMdDpcAZNZ9asqvmTwJBAJfbjS90Dc4TbcqrCJntd7ZrDl8y
489m/35pcWJAsIapfwevu3DzD6Nh7J++4AJbmCbmq80a/RWGuMywKeFFjnMCQCNx
kM+4aM2voUVzHMvAbRMIELDr8yp3WyTuRhsXDAbXBTGKOtdpw+2LvRBZ+4tADvmh
dujwU71+3UOV3ymbXgsCQG6zcy5lkeXF+rxZ5aRwwxpiAJp/TAlVj8v6HZa8Iz/M
pHm3I6FAD9xcZhS2X8ETGtxurIqYUAZwq8uVEa8Oh7A
-----END RSA PRIVATE KEY-----

I’m not great at RSA stuff so I did some googling and found this really useful stackexchange post. To get my input looking like the post, I stripped the new lines and header/footer and saved it as key-stripped.txt. I also saved the integrity line to integrity.txt since I thought I might need it. What else are you going to do with an RSA key but decrypt something.

$ base64 -d < key-stripped.txt | openssl rsa -inform DER > out.key
$ openssl asn1parse < out.key
$ base64 -d integrity.txt >integrity.enc
$ openssl rsautl -decrypt -inkey out.key < integrity.enc > integrity.dec
$ cat integrity.dec
/supersecretvaultthiswaywowimtiredthisnameshouldprobablybealotbetterbutohwellitssolateandthectfisinlikeliteralhours

STEP 5

Now we’re able to visit the real vault located here.

It links us to a tar file called phils_magic.tar.

Inside of phils_magic.tar we have an apk and a notes file. The notes read:

They've captured me and made me use my talents for their own gain. If you are to find where I am you must use this android application and talk to the admin. He will know how to find me. As a precaution to Kane finding where I have gone, I have taken steps to reduce the chance of Kane being able to use talk to the admin through this app. My hopes are if you have gotten this far in your search for me, you will be able to break the apps security and reach out to the admin.
Once you are able to initate contact with the admin, use the phrase 'security through obscurity' in a sentence. This will let him know I sent you. The admin does not use many words, but may be able to help you find me.

My credentials to log into the application are: imnotphil:canttouchthis

I’ve installed the app on an android emulator that comes with the android sdk. When I try to initiate a discussion with admin, it tells me NOT ADMIN GROUP ID. GO AWAY.

The ChatActivity shows Group ID: 125212531244112

Let’s also fire up the Android Device Monitor, another useful part of the SDK. In the monitor log we see some giant strings coming from our application. Let’s save these as b_private_key.txt and b_user_group.txt

b_user_group just appears to have a bunch of repeated text. b_private key is a base64 representation of the private key, as we could have guessed.

Let’s dig deeper into the source here. I’ll use d2j-dex2jar.bat to convert the chatsalot apk to a jar file, and then use jd-gui to save the sources of the jar file.

Looking through the java, we see that we’re sending json objects to a login endpoint http://ec2-54-85-21-142.compute-1.amazonaws.com:6063/api/login, when I recreate this in fiddler I get a 500 internal server error, but debugger is turned on. Sweet now I know what login looks like.

@app.route('/api/login', methods=['POST'])
def login():    
	username = request.json.get('username')
	password = request.json.get('password')
	if username is None or password is None:
		abort(400) # missing arguments    
	if User.query.filter_by(username=username).first() is None:
	    abort(400) # user doesn't exist

If we also check out the endpoint for looking for admin, we see this function in the debugger output. `http://ec2-54-85-21-142.compute-1.amazonaws.com:6063/api/chatadmin

@app.route('/api/chatadmin', methods=['POST'])
def chatAdmin():    
	message = request.json.get('message')    
	groupid = request.json.get('groupid')    
	g = groupid.split(' ')[:3]    
	if str(groupid) != "106610671042110":        
		print "____",groupid, "____"        
		return (jsonify({'resp_msg':'YOU ARE NOT AN ADMIN. GO AWAY'}), 401)

Success!! So now we know the admin group id.

Using what we’ve seen from the source code of the app, we can recreate a call to the /api/chatadmin api endpoint and forge our request to include the group id we’ve just learned.

POST http://ec2-54-85-21-142.compute-1.amazonaws.com:6063/api/chatadmin HTTP/1.1
Content-Type: application/json
Host: ec2-54-85-21-142.compute-1.amazonaws.com:6063
Content-Length: 77

{
  "message": "security through obscurity",
  "groupid": "106610671042110"
}
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 238
Server: Werkzeug/0.11.11 Python/2.7.12
Date: Sun, 20 Nov 2016 21:33:00 GMT

{
  "resp_msg": "Ah, you must be searching for phil. While I can't tell you where he is, I can give you some data from our last conversation that may help you find him. https://drive.google.com/file/d/0Bw7N3lAmY5PCVlpvaW9tQUs1MVU/view"
}

STEP 6

Download the zip file at https://drive.google.com/file/d/0Bw7N3lAmY5PCVlpvaW9tQUs1MVU/view. Unpacking the zip, we have a bunch of images. One is noticably larger than the others, though it’s also a higher resolution, so no real surprise.

It also happens to have a base64 encoded string at the end of the file, which translates to fun4dv3n7ur35w17hph1l

It was soooo long

(In the last 30 minutes of the competition, after our team nearly spent 15 man hours on this challenge)

The 7-Zip manager UI showed a message that said

Warnings: There are some data after the end of the payload data
Physical Size: 2,262,768
Tail Size: 96

I then copied the last 96 bytes of the zip file to a separate file, extra_data.bin

$ tail -c 96 Copy\ of\ phil_vacation.zip > extra_data.bin

After copying the bytes to the file, I ran file to see if I could understand the file format:

$ file extra_data.bin
extra_data.bin: GPG symmetrically encrypted data (AES cipher)

Then I ran:

$ gpg --output test --decrypt extra_data.bin
gpg: AES encrypted data
gpg: gpg-agent is not available in this session
gpg: encrypted with 1 passphrase

Use the string we found earlier as the passphrase: fun4dv3n7ur35w17hph1l

Flag

RC3-2016-PhilTrip