soffensive blog

make and makefile

I am a C/C++ newbie, but occassionally I have to compile or build projects. Since make (and Makefiles) are quite prevalent and sometimes they have to be adjusted due to potential errors, I had to learn more about them and want to share my learning publicly here.

Building Blocks

First of all, what are the involved building blocks of make and Makefiles?

  • make:
    • The GNU make utility. This is the executable that you actually run in order to execute a series of commands in order to modify files, typically compiling programs.
    • If you run the program without specifying an explicit input file with the -f option, make will look for the makefiles GNUmakefile, makefile, and Makefile, in that order.
    • make updates a target if it depends on prerequisite files that have been modified since the target was last modified, or if the target does not exist.
  • makefile:
    • This is the input file for the make utility and consists of a series of instructions how to modify files.
    • A makefile can contain one or more rules.
  • rule:
    • A rule consists of one or more targets, prerequisites and commands.
  • target:
    • A target is a file name and typically, there is only one per rule.
  • prerequisite:
    • The prerequisites are file names, separated by spaces. These files need to exist before the commands for the target are run. These are also called dependencies.
  • command:
    • The commands are a series of steps typically to make the target. They need to start with a tab character, not spaces.

The general format of a Makefile is as follows:

XXE with .NET in 2019

After the seminal blog post by James Jardine in 2016 on XXE exploitation in .NET applications back in 2016, Microsoft seems to have implemented some additional changes regarding the default behavior of XML parsers.

We work through the different XML methods provided and their corresponding vulnerable configurations. For all experiments, .NET framework 4.6 was chosen.

TL;DR

In order to create an XXE vulnerability for applications using .NET framework 4.6+, you have to instantiate a vulnerable XmlResolver beforehand.

Exploiting Blind File Reads / Path Traversal Vulnerabilities on Microsoft Windows Operating Systems

In a recent engagement I was confronted with a blind path traversal vulnerability on a server running with the Microsoft Windows operating system. That is, it was not possible to display folder contents but the complete file name and path had to be guessed. Due to the lack of a comprehensive website I was forced to gather information from various different sources.

In this blog post, I want to summarize my findings and focus on the exploitation of  this kind of vulnerability.

Exploiting misconfigured CORS Null Origin

Almost two years ago, in October 2016, James Kettle published an excellent blog post about the various types of Cross-Origin Resource Sharing (CORS) misconfigurations and how they can be exploited.

Recently, I encountered a web application that allowed for two-way interaction with the so-called null origin. More precisely, when sending an HTTP request specifying the header:

1
Origin: null

the server would respond with the following two HTTP headers:

Using angr and symbolic execution for reverse engineering challenges (RPI MBE Labs)

This blog posts will highlight how you can utilize the angr dynamic binary analysis framework and symbolic execution for reverse engineering tasks.

More precisely, we will look at the first two tasks in the lab1 of the RPISEC MBE labs.

While angr’s internals are quite complex and require substantial effort for mastering, getting started for our simple examples requires not too much knowledge.  

lab1C

The first example we will look at is lab1C from lab01, which requires the user to enter a certain password:

pwnable.kr: crypto1 challenge

In the pwnable.kr challenge crypto1 in the rookies section, we are given the following two files client.py and server.py:

client.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#!/usr/bin/python
from Crypto.Cipher import AES
import base64
import os, sys
import xmlrpclib
rpc = xmlrpclib.ServerProxy("http://localhost:9100/")

BLOCK_SIZE = 16
PADDING = '\x00'
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING
EncodeAES = lambda c, s: c.encrypt(pad(s)).encode('hex')
DecodeAES = lambda c, e: c.decrypt(e.decode('hex'))

# server's secrets
key = 'erased. but there is something on the real source code'
iv = 'erased. but there is something on the real source code'
cookie = 'erased. but there is something on the real source code'

# guest / 8b465d23cb778d3636bf6c4c5e30d031675fd95cec7afea497d36146783fd3a1
def sanitize(arg):
	for c in arg:
		if c not in '1234567890abcdefghijklmnopqrstuvwxyz-_':
			return False
	return True

def AES128_CBC(msg):
	cipher = AES.new(key, AES.MODE_CBC, iv)
	return EncodeAES(cipher, msg)

def request_auth(id, pw):
	packet = '{0}-{1}-{2}'.format(id, pw, cookie)
	e_packet = AES128_CBC(packet)
	print 'sending encrypted data ({0})'.format(e_packet)
	sys.stdout.flush()
	return rpc.authenticate(e_packet)

if __name__ == '__main__':
	print '---------------------------------------------------'
	print '-       PWNABLE.KR secure RPC login system        -'
	print '---------------------------------------------------'
	print ''
	print 'Input your ID'
	sys.stdout.flush()
	id = raw_input()
	print 'Input your PW'
	sys.stdout.flush()
	pw = raw_input()

	if sanitize(id) == False or sanitize(pw) == False:
		print 'format error'
		sys.stdout.flush()
		os._exit(0)

	cred = request_auth(id, pw)

	if cred==0 :
		print 'you are not authenticated user'
		sys.stdout.flush()
		os._exit(0)
	if cred==1 :
		print 'hi guest, login as admin'
		sys.stdout.flush()
		os._exit(0)

	print 'hi admin, here is your flag'
	print open('flag').read()
	sys.stdout.flush()

server.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/usr/bin/python
import xmlrpclib, hashlib
from SimpleXMLRPCServer import SimpleXMLRPCServer
from Crypto.Cipher import AES
import os, sys

BLOCK_SIZE = 16
PADDING = '\x00'
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING
EncodeAES = lambda c, s: c.encrypt(pad(s)).encode('hex')
DecodeAES = lambda c, e: c.decrypt(e.decode('hex'))

# server's secrets
key = 'erased. but there is something on the real source code'
iv = 'erased. but there is something on the real source code'
cookie = 'erased. but there is something on the real source code'

def AES128_CBC(msg):
	cipher = AES.new(key, AES.MODE_CBC, iv)
	return DecodeAES(cipher, msg).rstrip(PADDING)

def authenticate(e_packet):
	packet = AES128_CBC(e_packet)

	id = packet.split('-')[0]
	pw = packet.split('-')[1]

	if packet.split('-')[2] != cookie:
		return 0	# request is not originated from expected server
	
	if hashlib.sha256(id+cookie).hexdigest() == pw and id == 'guest':
		return 1
        if hashlib.sha256(id+cookie).hexdigest() == pw and id == 'admin':
                return 2
	return 0

server = SimpleXMLRPCServer(("localhost", 9100))
print "Listening on port 9100..."
server.register_function(authenticate, "authenticate")
server.serve_forever()

Analysis

Furthermore, there is a running instance of client.py at pwnable.kr on port 9006. Our goal is to connect to this service and retrieve the flag.