ふるつき

v(*'='*)v かに

Sunshine CTF 2019 writeup

I attended Sunshine CTF 2019 as a member of zer0pts. We came in the 10th place with 3255 points at the end of the CTF. I regret that I gave up to solve challenges during the competition.

I solved only two scripting challenges. I'm going to write up.

[Scripting 50 (125 Solves)]TimeWarp

Oh no! A t3mp0ral anoma1y has di5rup7ed the timeline! Y0u'll have to 4nswer the qu3stion5 before we ask them!

nc tw.sunshinectf.org 4101

Author: Mesaj2000

This was a numbers game challenge. The server demanded us to guess many numbers in 30 seconds. As I send my guessing number, the server returns the correct number that doesn't change in every attempt. So we could get the n-th correct number at the n-th attempt. I used the python script first, however, it was slow. So I rewrote it to the following simple shell script.

lines="39"  # the first correct number

while true; do
        newx=$(echo -e "$lines\n9999" | nc tw.sunshinectf.org 4101 | tail -2 | grep -o -E '^[0-9]+$')
        lines=$(echo -e "$lines\n$newx")
        echo $newx
done
I'm going to give you some numbers between 0 and 999.
Repeat them back to me in 30 seconds or less!
39
Alm0st there!
61
N1ce 0ne! Do it ag4in!

(...snip...)

Keep it up! The anoma1y is subsiding!
326
Icr3dible!
370
Wow! You did it!
As reward for fixing the timestream, here's the flag:
sun{derotser_enilemit_1001130519}

[Scripting 250 (47 Solves)]Entry Exam

I heard the Hart Foundation is accepting applications, see if you have what it takes by completing their entry exam.

http://ee.sunshinectf.org

Author: dmaria

The web page destributed a mark sheet as PNG format and took mathematics exams. To get the flag, we needed to solve 20 problems and mark the correct positions, submit a marked sheet in 2 seconds.

f:id:Furutsuki:20190401114026p:plain

Pillow is a very powerful python library for image manipulation. I used it to mark. Remaining tasks are easy: get the problems, solve them, and submit a marked sheet.

The flag was sun{7h3_b357_7h3r3_15_7h3_b357_7h3r3_w45_7h3_b357_7h3r3_3v3r_w1ll_b3}.

from PIL import Image, ImageDraw
import requests
import re

R = 25
DX = 68
DY = 90
XOFF = 362
XOFF2 = 852 - XOFF
YOFF = 460

def check_at(draw, problem, answer):
    x = XOFF + answer * DX
    if problem >= 11:
        x += XOFF2
        problem -= 10
    problem -= 1
    y = YOFF + problem * DY

    draw.ellipse((x-R, y-R, x+R, y+R), fill=0)

URL = 'http://ee.sunshinectf.org/exam'
s = requests.Session()

r = s.get(URL)
lines = r.text.splitlines()[1:-9]

while True:
    problem_num = 1
    img = Image.open("scantron.png").convert('L')
    draw = ImageDraw.Draw(img)

    for i in range(0, len(lines), 7):
        ans = str(eval(re.findall('>(.+)<', lines[i])[0].replace('/', '//')))
        hoge = None
        for j in range(2, 6):
            if ans == re.findall('>(.+)<', lines[i+j])[0]:
                hoge = j - 2
                break
        assert(hoge is not None)

        print(lines[i], ans, hoge, lines[i+hoge+2])
        check_at(draw, problem_num, hoge)
        problem_num += 1

    img.save('tmp.png')
    image = open('tmp.png', 'rb')
    files = {'file': ('tmp.png', image, 'image/png')}
    r = s.post(URL, files=files)
    lines = r.text.splitlines()

    print(lines[0])
    if 'Section' not in lines[0]:
        print(r.text)
        break
    lines = lines[1:-9]

Securinets Prequals 2K19 writeup

We made a new team zer0pts and attended Securinets Prequals 2K19. We got 23393 points and reached 2nd place!! Thanks to all the admins for this great CTF! I solved some of the challenges and I'm going to write up them.

f:id:Furutsuki:20190325085517p:plain

[Misc 200pts (321 solves)]HIDDEN

description:

My friend asked me to find his hidden flag in this link .. Can you help me? Link

Author:Tr'GFx

The web page of the link just has a simple sentence: "Flag is somewhere here". When I jumped to the link for the first time, Firefox alerted against the self-signed certificate. So I checked the certificate and found the flag at "Verified by" column. Securinets{HiDDeN_D@tA_In_S3lF_S3iGnEd_CeRtifICates}

[Misc 331pts (184 solves)]EZ

description:

Welcome to Securinets, this one is an easy one.

Please make sure you hash the WORD with sha1 (lowercase hash letter)

The final flag is : Securinets{the_hash_of_the_word}

Pic Link

Author:BlueWhale

We were given pic.zip which has an image file pic.png in it. By using stegsolve, I noticed that something is hidden in the Least Significant Bit. I wrote the following script to extract hidden data.

from PIL import Image

img = Image.open("pic.png")
w, h = img.size

s = ''
c = ''
for y in range(3):
    for x in range(w):
        r, g, b = img.getpixel((x, y))
        c += str(r&1) + str(g&1) + str(b&1)
        if len(c) >= 8:
            s += chr(int(c[:8], 2))
            c = c[8:]
print(s.rstrip('\x00'))

Then I got phrases from Sherlock Holmes. <DETELED_WORD> (!) is "memorandum-book", so the flag is Securinets{b47f0d2a8866a75696f94a515d0cdf54c7ea3174}.

--START--
"The fact is that upon his entrance I had instantly recognized the extreme
personal danger in which I lay. The only conceivable escape for him lay in silencing
my tongue. In an instant I had slipped the revolver from the drawer into my
pocket and was covering him through the cloth. At his remark I drew the weapon
out and laid it cocked upon the table. He still smiled and blinked, but there was
something about his eyes which made me feel very glad that I had it there,
"You evidently don't know me,' said he.
"'On the contrary,' I answered, 'I think it is fairly evident that I do. Pray take
a chair. I can spare you five minutes if you have anything to say.'
"'All that I have to say has already crossed your mind,' said he.
"'Then possibly my answer has crossed yours,' I replied.
"'You stand fast?'
"'Absolutely.'
"He clapped his hand into his pocket, and I raised the pistol from the table.
But he merely drew out a <DETELED_WORD> in which he had scribbled some
dates.
"You crossed my path on the fourth of January,' said he. 'On the twenty-third
you incommoded me; by the middle of February I was seriously inconvenienced
by you; at the end of March I was absolutely hampered in my plans; and now, at
the close of April, I find myself placed in such a position through your continual
persecution that I am in positive danger of losing my liberty. The situation is
becoming an impossible one.'
"'Have you any suggestion to make?' I asked.
"'You must drop it, Mr. Holmes,' said he, swaying his face about. 'You really
must, you know.'"
--END--

[Web 964pts (44 solves)]Custom Location

Try to find out the database credentials.

The author changed the location of some files to protect the web application from script kiddies.

Link

Author:TheEmperors

As I tried to access to the path such as https://web0.ctfsecurinets.com/hoge, the debug mode 404 page was shown. It had the function to see the source code. I saw the config/bootstrap.php and found that the env file was /secret_ctf_location/env. So I also saw it from this link: https://web0.ctfsecurinets.com/_profiler/open?file=secret_ctf_location/env. The flag was Securinets{D4taB4se_P4sSw0Rd_My5qL_St0L3n}.

[Crypto 962pts (50 solves)]MAZE

we've intercepted a message that we want to decrypt! but we couldn't find the key! can u help ?

Author : KERRO

The zip file was provided. It included 101 RSA public key files and cipher.txt. My teammate st98 found there were two keys whose gcd was not 1. This fact implied that two keys had the same prime, namely n1 = p * q1 and n2 = p * q2. Since gcd(n1, n2) is p, it can be factorized. The following script decrypted the cipher.txt.

from Crypto.PublicKey import RSA
from Crypto.Util.number import *
from base64 import b64decode
import fractions


n1 = 23489536169894875104380319731091524594886928982079989680685140526506816078328377365920912691345973867274127369888617266471562817001630072737234558761977577075038991165371860879920389022518216143091522409148685349425962144785062882226489262290433631048454159440985148197906498710065684391869085391454754106309032049154232850533299594084654876542951785594662744724164946205787746362648504615426049549895862885960678401490612936954071297209796703651121038358809482596283354654704634698014090659491829169711549185505494879482606511678080905510586288124335730218605304747220982982161819303534160762335592895244302851836981
n2 = 23260716557375690457724340517814798553284093383675955753210132374509973258283306822538580132700875733321460692101694179361245119306418651193402512612500111442624876103473535129327037097046343634997541541496318494961543987552228754832236044259856000320983983126129412431801144031562287397570846392952905862981221569085591696654562289384531854207702626277469166158114197478525681143466552721501485707709954322005798540444098755630199517759570465455471064172816576843800829708415595842816666071002921806841594943525213770657127124965423586840200929234600612382079511164305586033156711399178225762365306090386434107266037
p = 168736462866079204789584058199620418225526506348478399447895958829038354002285480486576728303147995561507709511105490546002439968559726489519296139857978907240880718150991015966920369123795034196767754935707681686046233424449917085120027639055362329862072939086970892956139024391556483288415208981014264336691
q1 = 139208418683860744636489594107518498051692876942105482068436575406002091300025595750940476658875774324613311765708231971440632450100860632595797604226237831396754383891914573698131769762436941837224713009721577421233571830899874638297795728204831707647487557389464078420524002550428515370686466308350190419191
q2 = 137852341825115687630372545540234125575043643297743715914372468140743017665122928684176567678186288631724569119078697598260381091322877334920545216266418987980787824645288016924652387350842372904949656504253960440751217710040954075691996893620788950284865727480192510130305432030965910622333944701850333681207
assert(n1 == p * q1)
assert(n2 == p * q2)
phi1 = (p-1) * (q1-1)
phi2 = (p-1) * (q2-1)
e = 65537
d1 = inverse(e, phi1)
d2 = inverse(e, phi2)

C = int(open("cipher.txt", "r").read().strip())

print(long_to_bytes(pow(C, d1, n1)))
print(long_to_bytes(pow(C, d2, n2)))

The flag was securinets{rs4_1s_g00d_s0m3t1m3s!}

[Rev 919pts (65 solves)]AutomateMe

Huuuuge!

Authors : KERRO && Anis_Boss

64-bit ELF file was given. It was a simple crackme challenge. It had so many tiny functions that IDA couldn't show the graph, however, every function was pretty simple and had the same structure. I wrote the following script to recover the correct input.

import re


lines = open("dis.asm").read().splitlines()
i = 0
flagbuf = ['' for _ in range(0x1000)]
while i < len(lines):
    if lines[i] == 'mov    rax,QWORD PTR [rbp-0x20]':
        i += 3

        index = 0
        if lines[i].startswith('add'):
            r = re.findall(r',(.+)$', lines[i])
        else:
            r = re.findall(r'0x(.+)\]', lines[i])
        if len(r) == 1:
            index = int(r[0], 16)

        i += 1
        if lines[i].startswith('cmp'):
            pass
        else:
            i += 1
            if lines[i].startswith('cmp'):
                r = re.findall(r'0x(.+)$', lines[i])
                print(r[0], lines[i])
                flagbuf[index] = chr(int(r[0], 16))
            else:
                r = re.findall(r',0x(.+)$', lines[i])
                xor = r[0]
                i += 1
                r = re.findall(r',0x(.+)$', lines[i])
                c = r[0]
                flagbuf[index] = chr(int(xor, 16) ^ int(c, 16))
    else:
        i += 1
print(''.join(flagbuf))

The flag was included in the correct input securinets{automating_everything_is_the_new_future}.

[Rev 1000pts (7 solves)]Monster

Just give me the flag!

nc 54.87.182.197 1337

Author : KERRO

We were given 32-bit ELF file and dummy flag.txt. If we could input the correct value, the binary would execute cat flag.txt.

I reversed it using IDA's graph view, ghidra's decompiler, and gdb-peda. As I analysed the binary, I found the following facts:

  • the input format is %llx which means it's like d3adb33f
  • it calculate some hash value of tsebehtsignisrever using input as the seed and compare it to ca 3d 3b 5b 4c 9d d2 cb dd 17 8d dc b9 49 3b ea 12 25
  • the seed is used byte to byte

I focused on the last fact. It was possible to give all 256 patterns to the binary and get the first byte of correct seed. The following command did it.

$ for i in `seq 255`; do printf $i; printf '%02x\n' $i | ltrace ./rev 2>&1; done > trace

The first byte was 0xbe and nad the next byte could be found in the same way, which was 0xfe. The correct seed was febe and got the flag securinets{mD5_EncOd1nG_iS_Be4uT1fuL}. It was first blood.

UTCTF Quals 2019 Writeup

I participated in the UTCTF Quals 2019 as a member of a team insecure. We reached 18th place with 8250points. Many interesting challenges were provided in the competition. Thanks to all the admins! I'm writing up some challenges which I solved.

[Cryptography 200pts][basics]crypto

description:

Can you make sense of this file?

by balex

We were given a file: binary.txt which had many binary-formed integers.

01010101 01101000 00101101 01101111 01101000 00101100 00100000 01101100 01101111 01101111 01101011 01110011 00100000 01101100 01101001 01101011 01100101 00100000 01110111 01100101 00100000 01101000 01100001 01110110 01100101 00100000 01100001 01101110 01101111 01110100 01101000 01100101 01110010 00100000 01100010 01101100 01101111 01100011 01101011 00100000 01101111 01100110 00100000 01110100 01100101 01111000 01110100 00101100 00100000 01110111 01101001 01110100 01101000 00100000 01110011 01101111 01101101 01100101 00100000 01110011 01101111 01110010 01110100 00100000 01101111 01100110 00100000 01110011 01110000 01100101 01100011 01101001 01100001 01101100 00100000 01100101 01101110 01100011 01101111 01100100 01101001 01101110 01100111 00101110 00100000 01000011 01100001 01101110 00100000 01111001 01101111 01110101 00100000 01100110 01101001 01100111 01110101 01110010 01100101 00100000 01101111 01110101 01110100 00100000 01110111 01101000 01100001 01110100 00100000 01110100 01101000 01101001 01110011 00100000 01100101 01101110 01100011 01101111 01100100 01101001 01101110 01100111 00100000 01101001 01110011 00111111 00100000 00101000 01101000 01101001 01101110 01110100 ...

I decoded them to a sequence of characters and I got a base64 encoded string, which was the next part of this challenge.

Uh-oh, looks like we have another block of text, with some sort of special encoding. Can you figure out what this encoding is? (hint: if you look carefully, you'll notice that there only characters present are A-Z, a-z, 0-9, and sometimes / and +. See if you can find an encoding that looks like this one.)
TmV3IGNoYWxsZW5nZSEgQ2FuIHlvdSBmaWd1cmUgb3V0IHdoYXQncyBnb2luZyBvbiBoZXJlPyBJdCBsb29rcyBsaWtlIHRoZSBsZXR0ZXJzIGFyZSBzaGlmdGVkIGJ5IHNvbWUgY29uc3RhbnQuIChoaW50OiB5b3UgbWlnaHQgd2FudCB0byBzdGFydCBsb29raW5nIHVwIFJvbWFuIHBlb3BsZSkuCmt2YnNxcmQsIGl5ZSdibyBrdnd5Y2QgZHJvYm8hIFh5ZyBweWIgZHJvIHBzeGt2IChreG4gd2tpbG8gZHJvIHJrYm5vY2QuLi4pIHprYmQ6IGsgY2VsY2RzZGVkc3l4IG1zenJvYi4gU3ggZHJvIHB5dnZ5Z3N4cSBkb2hkLCBTJ2ZvIGRrdW94IHdpIHdvY2NrcW8ga3huIGJvenZrbW9uIG9mb2JpIGt2enJrbG9kc20gbXJrYmttZG9iIGdzZHIgayBteWJib2N6eXhub3htbyBkeSBrIG5zcHBvYm94ZCBtcmtia21kb2IgLSB1eHlneCBrYyBrIGNlbGNkc2RlZHN5eCBtc3pyb2IuIE1reCBpeWUgcHN4biBkcm8gcHN4a3YgcHZrcT8gcnN4ZDogR28gdXh5ZyBkcmtkIGRybyBwdmtxIHNjIHF5c3hxIGR5IGxvIHlwIGRybyBweWJ3a2QgZWRwdmtxey4uLn0gLSBncnNtciB3b2t4YyBkcmtkIHNwIGl5ZSBjb28gZHJrZCB6a2Rkb2J4LCBpeWUgdXh5ZyBncmtkIGRybyBteWJib2N6eXhub3htb2MgcHliIGUsIGQsIHAsIHYgaywga3huIHEga2JvLiBJeWUgbWt4IHpieWxrbHZpIGd5YnUgeWVkIGRybyBib3drc3hzeHEgbXJrYmttZG9iYyBsaSBib3p2a21zeHEgZHJvdyBreG4gc3hwb2Jic3hxIG15d3d5eCBneWJuYyBzeCBkcm8gT3hxdnNjciB2a3hxZWtxby4gS3h5ZHJvYiBxYm9rZCB3b2RyeW4gc2MgZHkgZWNvIHBib2Flb3htaSBreGt2aWNzYzogZ28gdXh5ZyBkcmtkICdvJyBjcnlnYyBleiB3eWNkIHlwZG94IHN4IGRybyBrdnpya2xvZCwgY3kgZHJrZCdjIHpieWxrbHZpIGRybyB3eWNkIG15d3d5eCBtcmtia21kb2Igc3ggZHJvIGRvaGQsIHB5dnZ5Z29uIGxpICdkJywga3huIGN5IHl4LiBZeG1vIGl5ZSB1eHlnIGsgcG9nIG1ya2JrbWRvYmMsIGl5ZSBta3ggc3hwb2IgZHJvIGJvY2QgeXAgZHJvIGd5Ym5jIGxrY29uIHl4IG15d3d5eCBneWJuYyBkcmtkIGNyeWcgZXogc3ggZHJvIE94cXZzY3Igdmt4cWVrcW8uCnJnaG54c2RmeXNkdGdodSEgcWdmIGlzYWsgY3RodHVpa2UgZGlrIHprbnRoaGt4IHJ4cWxkZ254c2xpcSByaXN5eWtobmsuIGlreGsgdHUgcyBjeXNuIGNneCBzeXkgcWdmeCBpc3hlIGtjY2d4ZHU6IGZkY3lzbnszaHJ4cWxkMTBoXzE1X3IwMHl9LiBxZ2YgdnR5eSBjdGhlIGRpc2QgcyB5Z2QgZ2MgcnhxbGRnbnhzbGlxIHR1IHBmdWQgemZ0eWV0aG4gZ2NjIGRpdHUgdWd4ZCBnYyB6c3V0ciBiaGd2eWtlbmssIHNoZSB0ZCB4a3N5eXEgdHUgaGdkIHVnIHpzZSBzY2RreCBzeXkuIGlnbGsgcWdmIGtocGdxa2UgZGlrIHJpc3l5a2huayE=

I decoded it and I found the last part of the output was encrypted with the substitution cipher.

New challenge! Can you figure out what's going on here? It looks like the letters are shifted by some constant. (hint: you might want to start looking up Roman people).
kvbsqrd, iye'bo kvwycd drobo! Xyg pyb dro psxkv (kxn wkilo dro rkbnocd...) zkbd: k celcdsdedsyx mszrob. Sx dro pyvvygsxq dohd, S'fo dkuox wi wocckqo kxn bozvkmon ofobi kvzrklodsm mrkbkmdob gsdr k mybboczyxnoxmo dy k nsppoboxd mrkbkmdob - uxygx kc k celcdsdedsyx mszrob. Mkx iye psxn dro psxkv pvkq? rsxd: Go uxyg drkd dro pvkq sc qysxq dy lo yp dro pybwkd edpvkq{...} - grsmr wokxc drkd sp iye coo drkd zkddobx, iye uxyg grkd dro mybboczyxnoxmoc pyb e, d, p, v k, kxn q kbo. Iye mkx zbylklvi gybu yed dro bowksxsxq mrkbkmdobc li bozvkmsxq drow kxn sxpobbsxq mywwyx gybnc sx dro Oxqvscr vkxqekqo. Kxydrob qbokd wodryn sc dy eco pboaeoxmi kxkvicsc: go uxyg drkd 'o' crygc ez wycd ypdox sx dro kvzrklod, cy drkd'c zbylklvi dro wycd mywwyx mrkbkmdob sx dro dohd, pyvvygon li 'd', kxn cy yx. Yxmo iye uxyg k pog mrkbkmdobc, iye mkx sxpob dro bocd yp dro gybnc lkcon yx mywwyx gybnc drkd cryg ez sx dro Oxqvscr vkxqekqo.
rghnxsdfysdtghu! qgf isak cthtuike dik zknthhkx rxqldgnxsliq risyykhnk. ikxk tu s cysn cgx syy qgfx isxe kccgxdu: fdcysn{3hrxqld10h_15_r00y}. qgf vtyy cthe disd s ygd gc rxqldgnxsliq tu pfud zftyethn gcc ditu ugxd gc zsutr bhgvykenk, she td xksyyq tu hgd ug zse scdkx syy. iglk qgf khpgqke dik risyykhnk!

The online solver could solve it. The flag was utflag{3ncrypt10n_15_c00l}.

[Forensics 100pts][basics]forensics

description:

My friend said they hid a flag in this picture, but it's broken!

by balex

We were given a file which had an extension .jpeg, however, it was the ascii text utflag{d0nt_tru5t_f1l3_3xt3ns10n5}.

[Web 650pts]HabbyDabby's Secret Stash

description:

HabbyDabby's hidden some stuff away on his web server that he created and wrote from scratch on his Mac. See if you can find out what he's hidden and where he's hidden it!

http://a.goodsecurity.fail/

by copperstick6

This challenge's page had an LFI vulnerability. The query http://a.goodsecurity.fail/?file=/etc/passwd showed the contents of /etc/passwd. As the challenge description said that HabbyDabby used a Mac machine to develop the page, I tried reading the file .DS_Store, which is usucally created by the macOS automatically. It had the information about the directory structure. I used this library to view them. I explored some directories and found the flag at http://a.goodsecurity.fail/e/d/e/flag.txt. By the way, the LFI vulnerability wasn't necessary to solve this challenge. What did that mean?

[Reverse Engineering 400pts]Domain Generation Algorithm

description:

This executable calculates a new domain depending on the system time. See if you can predict what the new domain will be on Tue, 20 Apr 2021 13:25:03 GMT.

Note: the flag is utflag{domain_name.tld}

by jitterbug_gang

The given file dga was an ELF. It was created with pyinstaller. Pyinstaller stores compiled bytes in the ELF file. So we can extract it using archive_viewer.py.

By the way, the byte-compilation of python(CPython) has 3 steps. The first step is the conversion from source code to bytecode. We can use the builtin compile function for this. The next step is to marshal the bytecode, this step corresponds to marshal.dumps function. The last step is to create the .pyc format data. The structure of .pyc is magic + timestamp + padding + marshaled-bytecode. The bytes which we can extract from the ELF are the marshaled-bytecode.

I wrote the following script for formatting the extracted bytecode to .pyc format and making pycdc decompile it to a source code.

import marshal
import struct
import time
import imp
import sys
import os

with open(sys.argv[1], 'rb') as f:
    code = f.read()

t = struct.pack('i', int(time.time()))
padding = b'A\x00\x00\x00'
# bytecode = marshal.dumps(code)
bytecode = code

with open(sys.argv[1]+".pyc", 'wb') as f:
    f.write(imp.get_magic())
    f.write(t)
    f.write(padding)
    f.write(bytecode)

I could restore the original source code successfully. My last work was to modify the code so that it prints the generated domain and uses a specified time.

# Source Generated with Decompyle++
# File: dga.pyc.pyc (Python 3.6)

from nistbeacon import NistBeacon
import time
from datetime import datetime
import hashlib

def gen_domain():
    # now = int(time.time())
    now = datetime.strptime('2021-04-20 13:25:03 +0000', '%Y-%m-%d %H:%M:%S %z').timestamp()
    now -= 100000000
    record = NistBeacon.get_previous(now)
    val = record.output_value
    h = hashlib.md5()
    h.update(str(val).encode('utf-8'))
    res = h.digest()
    domain = ''
    for ch in res:
        tmp = (ch & 15) + (ch >> 4) + ord('a')
        if tmp <= ord('z'):
            domain += chr(tmp)
    domain += '.org'
    return domain

if __name__ == '__main__':
    print(gen_domain())

The flag was: yervwuusmmiis.org.

[Reverse Engineering 750pts]simple python script

description:

simple python script I wrote while not paying attention in graphics

by asper

We were given a python script whose name was wtf.py. It was obfuscated as shown below. Wow there are cats!

flag = input("> ")
for i in range(0, len(flag), int((544+5j).imag)):
    inputs = []
    (lambda ねこ, _, __, ___, ____, _____, ネコ, q, k: getattr(ねこ, "extend")([(lambda _, __, ___: _(_, __, ___))(lambda _, __, ___:bytes([___ % __]) + _(_, __, ___ // __) if ___ else(lambda: _).__code__.co_lnotab,(_ << k),(((q << ネコ) - _____) << ((((_____ << __) - _) << ____) + _____)) + (((q << ネコ) - ((___ << __) + _)) << ((((_____ << __) - _) << ____) - q))...
    getattr(temp, "update")(getattr(flag[i:i + 5], "encode")("utf-8"))
    if getattr(__import__("difflib"), "SequenceMatcher")(None, getattr(getattr(temp, "hexdigest")(), "lower")(), getattr(inputs[i // 5], "decode")("utf-8").lower()).ratio() != 1.0:
        exit()

print("correct")

I think the print debug is effective in this sort of challenges. I categorized the nested lambda expression into 2 parts: the function-call part and the arguments-prepare part. Then I understood the work of this code. I simplified the obfuscated code into the following script.

s = input()
hashes = ['26d33687bdb491480087ce1096c80329aaacbec7', '1c3bcf656687cd31a3b486f6d5936c4b76a5d749', '11a3e059c6f9c223ce20ef98290f0109f10b2ac6', '6301cb033554bf0e424f7862efcc9d644df8678d', '95d79f53b52da1408cc79d83f445224a58355b13']
for i in range(0, len(s), 5):
  if sha1(s[i:i+5]).hexdigest() != hashes[i//5]:
    print("wrong")
    exit()
print("correct")

I found that the input string was checked in sha1 every 5-byte block. To find the correct input I cracked these hashes. Because the original text were just 5 characters long, bruteforce worked. The flag was puppyp1zzaanimetoruskitty.

[Reverse Engineering 1200pts]Crackme

description:

Attention all UTCTF players, asper is in great danger, and he needs YOUR help to reverse engineer this binary and figure out the password. To do this, he needs IDA Pro and a couple of breakpoints. To help him, all he needs is your credit card number, the three numbers on the back, and the expiration month and date. But you gotta be quick so that asper can secure the flag, and achieve the epic victory R O Y A L.

Note: the flag is the password with utflag{} wrapped around it.

by jitterbug_gang

Also, this binary was compiled a little differently, and you may need to install some extra dependencies to run it. (Or you can try solving this with just static analysis.) Try installing libc++abi-dev and libcxxtools-dev to run this challenge.

If that doesn't work for you, try to preload this libc file with LD_PRELOAD.

At first I replaced __libc_csu_init with nop because ptrace prevented me from debugging dynamically. I used radare2 for this work.

By analysing the binary dynamically & statically, I found that the binary was working like the following C code. In fact, this binary used an exception for jumping to somewhere in order to make it complicated. Also the loop I commented stuff was constructed on the memory at runtime.

char test[] = {...};
int main() {
    char buf[0x40];
    fgets(buf, 0x40, stdin);
    buf[0x34] ^= 0x43;
    buf[0x2f] ^= 0x44;
    for (int i = 0; i < strlen(buf); i++) {
        buf[i] ^= 0x27;
    }
    for (int i = 0; i < strlen(buf); i++) { // stuff
        buf[i] ^= (i + 0x33);
    }
    if (memcmp(buf, test, 0x40) == 0) {
        printf("correct\n");
    } else {
        printf("wrong\n");
    }
}

The correct input could be calculated by the following script.

data = [0x5, 0x4C, 0x7A, 0x70, 0x66, 0x2C, 0x41, 0x2C, 0x72, 0x7D, 0x2A, 0x6B, 0x75, 0x6, 0x12, 0x54, 0x54, 0xD, 0x3D, 0x15, 0x8, 0xE, 0x1A, 0x32, 0x1B, 0x5A, 0x6, 0x5, 0x37, 0x1B, 0x13, 0x14, 0x10, 0x2C, 0x6, 0x41, 0x2F, 0xB, 0x16, 0x4E, 0x23, 0x1A, 0x8, 0xB, 0x4B, 0x34, 0x32, 0x5E, 0x74, 0x25, 0x1D, 0x22, 0x33, 0x3F, 0x3E, 0x7E, 0x3E, 0x38, 0x3E, 0x20, 0x2B, 0x3C, 0x60]

for i in range(0, len(data)):
    data[i] = data[i] ^ (i + 0x33)

for i in range(0, len(data)):
    data[i] = data[i] ^ 0x27

data[0x34] = data[0x34] ^ 0x43
data[0x2f] = data[0x2f] ^ 0x44

print(repr("".join(map(chr, data))))

The result was \x11_hav3_1nf0rmat10n_that_w1ll_lead_t0_th3_arr3st_0f_c0pp3rstick6. The first character seemed wrong, but easy to guess the correct value was 1. The correct input was 1_hav3_1nf0rmat10n_that_w1ll_lead_t0_th3_arr3st_0f_c0pp3rstick6 and the flag was utctf{1_hav3_1nf0rmat10n_that_w1ll_lead_t0_th3_arr3st_0f_c0pp3rstick6}.