NorzhCTF 2021: Secure Auth v0

Secure Auth v0

Category: Airport hall/reverse

chal

20 points

One of NorzhNuclea’s developers joined the team last quarter, specialized in authentication systems he found one he developed a few years ago with a innovative obfuscation method. Find the correct password to validate the checks.

by Masterfox

file: chall.zip

Solution

In archive I found binary. And as I’m noob when it comes to binaries I’ve started with very basics.

file chall
chall: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2,
 BuildID[sha1]=2d7a473fecb4f2cc06b09e9652f52db5b4605f67, for GNU/Linux 3.2.0, stripped

Ghidra has shown it’s filled with large number of nops. Once executed it behaves like below.

./chall 
testinput
Failed !

I used strace and ltrace to have a look what’s happening underneath. First one didn’t get me anything interesting, second one lead me to the solution…

ltrace ./chall 
__isoc99_scanf(0x49c8031, 0x7ffd16e0d400, 0x7ffd16e0d558, 0x7f3cd5f11718testinput
) = 1
strlen("testinput")                                             = 9
strcmp("Z)l*O(o!Z", "c-n|TD^zJFp|I'q"VCj7.mNj4")                = -9
puts("Failed !"Failed !
)                                                = 9
+++ exited (status 1) +++

I’ve taken few tests as below.

(ctf) luc@slon:~/norzh$ ltrace ./chall
__isoc99_scanf(0x49c8031, 0x7ffcc92e5d80, 0x7ffcc92e5ed8, 0x7fd921f9d718aaaaaaaaaaaaaaaaaaaaaa
) = 1
strlen("aaaaaaaaaaaaaaaaaaaaaa")                                = 22
strcmp("Gt]|Gt]|Gt]|Gt]|Gt]|Gt", "c-n|TD^zJFp|I'q"VCj7.mNj4")   = -28
puts("Failed !"Failed !
)                                                = 9
+++ exited (status 1) +++
(ctf) luc@slon:~/norzh$ ltrace ./chall 
__isoc99_scanf(0x49c8031, 0x7fffc8444a90, 0x7fffc8444be8, 0x7f0221ec2718aaaa
) = 1
strlen("aaaa")                                                  = 4
strcmp("Gt]|", "c-n|TD^zJFp|I'q"VCj7.mNj4")                     = -28
puts("Failed !"Failed !
)                                                = 9
+++ exited (status 1) +++
(ctf) luc@slon:~/norzh$ ltrace ./chall 
__isoc99_scanf(0x49c8031, 0x7fff896af700, 0x7fff896af858, 0x7f3fac6df718baaa
) = 1
strlen("baaa")                                                  = 4
strcmp("Gt]}", "c-n|TD^zJFp|I'q"VCj7.mNj4")                     = -28
puts("Failed !"Failed !
)                                                = 9
+++ exited (status 1) +++
(ctf) luc@slon:~/norzh$ ltrace ./chall
__isoc99_scanf(0x49c8031, 0x7fffc8aa35e0, 0x7fffc8aa3738, 0x7f800d8c3718bbbb
) = 1
strlen("bbbb")                                                  = 4
strcmp("Hu^}", "c-n|TD^zJFp|I'q"VCj7.mNj4")                     = -27
puts("Failed !"Failed !
)                                                = 9
+++ exited (status 1) +++
(ctf) luc@slon:~/norzh$ ltrace ./chall
__isoc99_scanf(0x49c8031, 0x7ffd0d8e9eb0, 0x7ffd0d8ea008, 0x7f52a9922718~~~~
) = 1
strlen("~~~~")                                                  = 4
strcmp("d2z:", "c-n|TD^zJFp|I'q"VCj7.mNj4")                     = 1
puts("Failed !"Failed !
)                                                = 9
+++ exited (status 1) +++

I came to below conclusions:

  • it looks like input is shifted in groups of 4 characters,
  • shifts are -26, -76, -4, -68,
  • whole input is reversed,
  • shifted/encrypted input is compared with c-n|TD^zJFp|I'q"VCj7.mNj4 string, which may be encrypted flag or some kind of secret.

I’ve prepared below script to decrypt the string (ok, at this moment I already know it was the flag).

encoded = 'c-n|TD^zJFp|I\'q"VCj7.mNj4'
shifts = [-26, -76, -4, -68]

def encode(input):
    limit = min(4, len(input))
    chars = [ord(input[i]) + shifts[i] for i in range(limit)]
    for i in range(len(chars)):
        if chars[i] < 31:
            chars[i] = 126 + chars[i] - 31
    return [chr(i) for i in chars]

def decode(input):
    limit = min(4, len(input))
    chars = [ord(input[i]) - shifts[i] for i in range(limit)]
    for i in range(len(chars)):
        if chars[i] < 31:
            chars[i] = 126 - chars[i]
        if chars[i] > 126:
            chars[i] = 31 + chars[i] - 126
    return [chr(i) for i in chars]

def test():
    test_string = '~~~~{}""_TESTTESTLMNO/zkRANDOMSTRING'
    test_encoded = []
    for i in range(0, len(test_string), 4):
        test_encoded += encode(test_string[i:i + 4])
    test_decoded = []
    for i in range(0, len(test_encoded), 4):
        test_decoded += decode(test_encoded[i:i + 4])
    assert test_string == ''.join(test_decoded)

test()
flag = []
for i in range(0, len(encoded), 4):
    flag += decode(encoded[i:i+4])
flag.reverse()
print('Flag: {}'.format(''.join(flag)))

Output:

Flag: NORZH{n0pfuscat3d_b1nary}

Ok, so in fact the challenge didn’t require deep analysis and reversing of binary, just a bit of perceptiveness ;-)

Flag

NORZH{n0pfuscat3d_b1nary}

Privacy Policy
luc © 2021