Density
This challenge contains an executable and an encoded data file generated by it. We need to reverse the encoding:
1
2
3
4
5
$ ./b64pack
usage: ./befshar input
$ ./b64pack aaa
?????k??????n??
The logic can be quickly analyzed in Hex Rays or Snowman, or traced in the debugger. Once the parameter is supplied the following chunk of code does the processing of it (see comments inside):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
...
.text:000055594AC08C3D loc_55594AC08C3D: ; CODE XREF: main+20?j
.text:000055594AC08C3D xor eax, eax
.text:000055594AC08C3F call sub_55594AC08DE0 ; Generate a random string composed of printable characters
.text:000055594AC08C44 mov r12, rax
.text:000055594AC08C47 xor eax, eax
.text:000055594AC08C49 call sub_55594AC08DE0 ; Generate another random string
.text:000055594AC08C4E mov rsi, [rbp+8] ; src
.text:000055594AC08C52 mov rbx, rax
.text:000055594AC08C55 mov rdi, r12 ; src
.text:000055594AC08C58 call sub_55594AC08F40 ; Append command line string to first random string
.text:000055594AC08C5D mov rsi, rbx ; src
.text:000055594AC08C60 mov rdi, rax ; src
.text:000055594AC08C63 call sub_55594AC08F40 ; Append second random string to the result
.text:000055594AC08C68 mov rbx, rax
.text:000055594AC08C6B or rcx, 0FFFFFFFFFFFFFFFFh
.text:000055594AC08C6F xor eax, eax
.text:000055594AC08C71 mov rdi, rbx
.text:000055594AC08C74 lea rsi, [rsp+28h+var_20]
.text:000055594AC08C79 repne scasb ; Find resulting string length
.text:000055594AC08C7B mov rdi, rbx
.text:000055594AC08C7E mov rax, rcx
.text:000055594AC08C81 not rax
.text:000055594AC08C84 sub rax, 1
.text:000055594AC08C88 mov [rsp+28h+var_20], rax
.text:000055594AC08C8D call sub_55594AC08FB0 ; Encode the string
.text:000055594AC08C92 mov rsi, [rsp+28h+var_20]
.text:000055594AC08C97 mov rdi, rbx
.text:000055594AC08C9A call sub_55594AC094F0 ; ...and print it
.text:000055594AC08C9F mov edi, 0Ah ; c
.text:000055594AC08CA4 call _putchar
.text:000055594AC08CA9 jmp loc_55594AC08C13
...
Encoding logic in sub_55594AC08FB0
is as follows:
- Convert each character from set
@$_!\"#%&'()*+,-./:;<=>?\n
to+
andchr(character position + ord('a'))
- Convert each character from set
[\\]^{|}~`\t
to++
andchr(character position + ord('a'))
- For all characters convert each to its position in Base64 character set (expressed as a 6-bit value) and glue these bit strings together to produce the result
To recover our encoded string let’s do these operations in reverse order:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
b64str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
punct1 = "@$_!\"#%&'()*+,-./:;<=>?\n"
punct2 = "[\\]^{|}~`\t"
data = bytearray(open('short','rb').read())
# convert to bitstring
bitstring = ''.join(['{:08b}'.format(x) for x in data])
# unpack every 6 bits into a Base64 characater
decoded = ''
for x in range(0,len(bitstring),6):
decoded += b64str[int(bitstring[x:x+6],2)]
# decode special "+" encoding
out = ''
i = 0
while i < len(decoded):
if decoded[i] == '+':
i += 1
if decoded[i] == '+':
i += 1
out += punct2[ord(decoded[i])-ord('a')]
else:
out += punct1[ord(decoded[i])-ord('a')]
else:
out += decoded[i]
i += 1
print out
Running the script produces the flag:
1
2
$ python solve.py
O~$/cASIS{01d_4Nd_GoLD_ASIS_1De4_4H4t_g0e5_f0r_ls!}dI )M>b|D9W//CC
The flag is ASIS{01d_4Nd_GoLD_ASIS_1De4_4H4t_g0e5_f0r_ls!}
.