mobile1
My friend sent this file to me and said that there was a flag in it. Can you help me?https://drive.google.com/open?id=1iglx4cQ_iVi1RABBa1eF0OXcOGECjVLy
.ipa 파일을 받을 수 있다.
위키를 보면 .ipa파일은 .zip으로 변경 후 압축해제가 가능하다고 나와있다.
https://en.wikipedia.org/wiki/.ipa
Files with the .ipa extension can be uncompressed by changing the extension to .zip and unzipping.
또한 위키와 다음 링크에서 info.plist 파일에는 메타데이터와 같은 다양한 정보가 담겨있다고 한다.
info.plist 파일의 문자열을 확인해보면
This obnoxious kid with spiky hair keeps telling me his key can open all doors.
Can you generate a key to open this program before he does?
Connect to challenges.auctf.com 30004
sub_10C0("Give me a key!");
sub_1100(&v7, 30LL, stdin);
v4 = (const char *)&v7;
if ( encrypt(&v7) )
{
print_flag();
result = 0;
}
입력받은 시리얼을 인자로 encrypt
함수를 실행하여 반환값이 True 일 경우에 플래그를 출력해준다.
signed __int64 __fastcall encrypt(__int64 a1)
{
unsigned __int64 v2; // rax@5
int i; // [sp-20h] [bp-20h]@1
__asm { rep nop edx }
for ( i = 0; ; ++i )
{
LODWORD(v2) = sub_10D0(secret);
if ( i >= v2 )
break;
if ( (8 * *(_BYTE *)(i + a1) + 19) % 61 + 65 != secret[i] )
return 0LL;
}
return 1LL;
}
입력된 시리얼 각각에 특정 연산을 수행하여 그 값이 secret
과 모두 동일하면 1을 반환한다.
모든 아스키 문자에 대해 동일한 연산 후의 결과가 secret
인 값을 추출하여 원래의 시리얼 값을 구할 수 있다.
from pwn import *
table_ascii = 'abcdefghijklnmopqrstuvwxyzABCDEFGHIJKLNMOPQRSTUVWXYZ1234567890_+-={}[];\':",./<>?!@#$%^&*()'
secret = 'aQLpavpKQcCVpfcg'
def dec(ch):
global table_ascii
for x in table_ascii:
calc = (ord(x) * 8 + 19) % 61 + 65
if ord(ch) == calc:
return x
#calc dec
serial = bytearray(map(dec, list(secret)))
print 'serial is ['+serial+']'
p = remote('challenges.auctf.com', 30004)
print p.recvrepeat(0.2)
p.sendline(serial)
p.interactive()
플래그 값은 auctf{that_w@s_2_ezy_29302}
I'm learning assembly. Think you can figure out what this program returns?
Note: Not standard flag format. Please provide either the unsigned decimal equivalent or hexadecimal equivalent.
어셈블리 언어를 해석하는 문제다.
.file "plain_asm.c"
.intel_syntax noprefix
.text
.globl main
.type main, @function
main:
.LFB6:
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
sub rsp, 16
mov eax, 0
call func_1
mov DWORD PTR -4[rbp], eax
mov eax, 0
call func_2
mov DWORD PTR -8[rbp], eax
mov edx, DWORD PTR -8[rbp]
mov eax, DWORD PTR -4[rbp]
mov esi, edx
mov edi, eax
call func_3
mov DWORD PTR -12[rbp], eax
mov eax, 0
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE6:
.size main, .-main
.globl func_1
.type func_1, @function
func_1:
.LFB7:
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
mov BYTE PTR -1[rbp], 25
mov DWORD PTR -8[rbp], 0
jmp .L4
.L5:
mov eax, DWORD PTR -8[rbp]
add eax, 10
mov edx, eax
mov eax, edx
sal eax, 2
add eax, edx
lea edx, 0[0+rax*4]
add eax, edx
add BYTE PTR -1[rbp], al
add DWORD PTR -8[rbp], 1
.L4:
cmp DWORD PTR -8[rbp], 9
jle .L5
movzx eax, BYTE PTR -1[rbp]
mov DWORD PTR -12[rbp], eax
mov eax, DWORD PTR -12[rbp]
pop rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE7:
.size func_1, .-func_1
.globl func_2
.type func_2, @function
func_2:
.LFB8:
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
mov DWORD PTR -4[rbp], 207
mov eax, DWORD PTR -4[rbp]
pop rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE8:
.size func_2, .-func_2
.globl func_3
.type func_3, @function
func_3:
.LFB9:
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
mov DWORD PTR -36[rbp], edi
mov DWORD PTR -40[rbp], esi
cmp DWORD PTR -36[rbp], 64
jg .L10
mov eax, 24
jmp .L11
.L10:
cmp DWORD PTR -40[rbp], 211
jle .L12
mov eax, 20
jmp .L11
.L12:
cmp DWORD PTR -36[rbp], 0
je .L13
cmp DWORD PTR -40[rbp], 0
jne .L13
mov eax, 120
jmp .L11
.L13:
cmp DWORD PTR -36[rbp], 0
jne .L14
cmp DWORD PTR -40[rbp], 0
je .L14
mov eax, 220
jmp .L11
.L14:
mov eax, DWORD PTR -36[rbp]
or eax, DWORD PTR -40[rbp]
mov DWORD PTR -12[rbp], eax
mov eax, DWORD PTR -36[rbp]
and eax, DWORD PTR -40[rbp]
mov DWORD PTR -16[rbp], eax
mov eax, DWORD PTR -36[rbp]
xor eax, DWORD PTR -40[rbp]
mov DWORD PTR -20[rbp], eax
mov DWORD PTR -4[rbp], 0
mov DWORD PTR -8[rbp], 0
jmp .L15
.L16:
mov eax, DWORD PTR -16[rbp]
sub eax, DWORD PTR -8[rbp]
mov edx, eax
mov eax, DWORD PTR -12[rbp]
add eax, edx
add DWORD PTR -4[rbp], eax
add DWORD PTR -8[rbp], 1
.L15:
mov eax, DWORD PTR -8[rbp]
cmp eax, DWORD PTR -20[rbp]
jl .L16
mov eax, DWORD PTR -4[rbp]
.L11:
pop rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE9:
.size func_3, .-func_3
.ident "GCC: (Debian 9.2.1-22) 9.2.1 20200104"
.section .note.GNU-stack,"",@progbits
형변환과 반복문으로 인해 눈으로 풀 순 없었다.
어셈블리 언어를 그대로 파이썬으로 작성하여 문제를 해결했다.
피연산자 크기에 따라 다른 결과가 나오므로, 연산자를 다시 정의하여 사용했다.
rax = 0
rdx = 0
high = 0xffffffff00000000
low = 0xffffffff
def b_plus(val, add):
return (val & 0xffffffffffffff00) + ((val + add) & 0xff)
def dw_and(val, add):
return (val & high) | ((val & add) & low)
def dw_xor(val, add):
return (val & high) | ((val ^ add) & low)
def dw_or(val, add):
return (val & high) | ((val | add) & low)
def dw_plus(val, add):
return (val & high) | ((val + add) & low)
def dw_minus(val, add):
return (val & high) | ((val - add) & low)
def dw_mul(val, add):
return (val & high) | ((val * add) & low)
def dw_sal(val, count):
sign = 1 << (32 - 1)
if val | sign == val:
val = val << count
val = val | (1 << (32 - 1))
else:
val = val << count
return val
def func1():
rbp_1 = 25
rbp_8 = 0
while rbp_8 <= 9:
rax = rbp_8
rax = dw_plus(rax, 10)
rdx = rax
rax = rdx
rax = dw_sal(rax, 2)
rax = dw_plus(rax, rdx)
rdx = dw_mul(rax, 4)
rax = dw_plus(rax, rdx)
rbp_1 = b_plus(rbp_1, rax)
rbp_8 += 1
rax = rbp_1
rbp_12 = rax
rax = rbp_12
return rax
def func2():
rbp_4 = 207
rax = rbp_4
return rax
def func3(rdi, rsi):
rbp_36 = rdi
rbp_40 = rsi
if rbp_36 > 64:
if rbp_40 <= 211:
#L12
if rbp_36 == 0 or rbp_40 != 0:
#L13
if rbp_36 != 0 or rbp_40 == 0:
#L14
rax = rbp_36
rax = dw_or(rax, rbp_40)
rbp_12 = rax
rax = rbp_36
rax = dw_and(rax, rbp_40)
rbp_16 = rax
rax = rbp_36
rax = dw_xor(rax, rbp_40)
rbp_20 = rax
rbp_4 = 0
rbp_8 = 0
#L15
while rbp_8 < rbp_20:
#L16
rax = rbp_16
rax = dw_minus(rax, rbp_8)
rdx = rax
rax = rbp_12
rax = dw_plus(rax, rdx)
rbp_4 = dw_plus(rbp_4, rax)
rbp_8 += 1
rax = rbp_4
return rax
else:
rax = 220
return rax
else:
rax = 120
return rax
else:
rax = 20
return rax
else:
rax = 24
return rax
rbp_4 = func1()
print hex(rbp_4)
rax = 0
rbp_8 = func2()
ret = func3(rbp_4, rbp_8)
print 'result: ' + str(ret)
플래그 값은 28623
I've been working on my anti-reversing lately. See if you can get this flag!
Connect at challenges.auctf.com 30005
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [sp+0h] [bp-2018h]@1
char *key; // [sp+2000h] [bp-18h]@1
char *input_enc; // [sp+2004h] [bp-14h]@1
int v7; // [sp+2008h] [bp-10h]@1
int v8; // [sp+200Ch] [bp-Ch]@1
int *v9; // [sp+2014h] [bp-4h]@1
v9 = &argc;
setvbuf(stdout, 0, 2, 0);
puts("54 68 65 20 6d 61 6e 20 69 6e 20 62 6c 61 63 6b 20 66 6c 65 64 20 61 63 72 6f 73 73 20 74 68 65 20 64 65 73 65 72 74 2c 20 61 6e 64 20 74 68 65 20 67 75 6e 73 6c 69 6e 67 65 72 20 66 6f 6c 6c 6f 77 65 64 2e");
debugger_check();
v8 = 17;
v7 = 12;
printf("Input: ");
fgets(&s, 0x2000, stdin);
remove_newline(&s);
input_enc = encrypt(&s, v8, v7);
key = calloc(0x20u, 4u);
getString(key);
if ( !strcmp(key, input_enc) )
print_flag();
else
printf("Not quite");
return 0;
}
시리얼을 구하는 문제다.
입력값 s
가 encrypt()
에서 암호화되고
그 값이 key
에 저장될 암호화된 시리얼값과 일치하면 플래그를 출력해준다.
_BYTE *__cdecl encrypt(char *input, int num_17, int num_12)
{
size_t v3; // eax@1
_BYTE *dst; // [sp+8h] [bp-10h]@1
size_t i; // [sp+Ch] [bp-Ch]@1
debugger_check();
v3 = strlen(input);
dst = calloc(v3, 1u);
for ( i = 0; strlen(input) > i; ++i )
{
if ( input[i] == 32 )
dst[i] = input[i];
else
dst[i] = (num_17 * (input[i] - 65) + num_12) % 26 + 65;
}
return dst;
}
암호화 과정은 간단하며, 복호화할 필요없이 아스키테이블에서 해당 암호화를 거친 후에 비교 대상인 암호화된 시리얼과 동일한 문자를 구하면 된다.
unsigned int __cdecl getString(int p_str)
{
unsigned int result; // eax@5
unsigned int i; // [sp+8h] [bp-Ch]@1
int idx; // [sp+Ch] [bp-8h]@1
debugger_check();
idx = 0;
for ( i = 0; ; ++i )
{
result = i;
if ( i > 0x1F )
break;
if ( !(i & 1) )
*(15 - idx++ + p_str) = blah[i];
}
return result;
}
암호화된 시리얼 값을 가져오는 함수이다.
blah
의 짝수 인덱스에 저장되있는 값을 가져와서 역순으로 나열한다.
blah
의 원래 저장된 값은 상수이므로 IDA를 이용해서 확인할 수 있다.
파이썬으로 시리얼을 구하는 코드를 작성했다.
from pwn import *
import re
import time
table_ascii = 'abcdefghijklnmopqrstuvwxyzABCDEFGHIJKLNMOPQRSTUVWXYZ1234567890_+-={}[];\':",./<>?!@#$%^&*()'
key = """
X...A...P...R...M...
X...C...S...B...
C...E...D...I...
S...B...V...X...
I...S...X...W...
E...R...J...R...
W...S...Z...A...
R...S...Q...????
"""
pt = re.compile('[A-Z]')
key = bytearray(pt.findall(key))[0::2][::-1]
def dec(ch):
#print 'ch: ' + str(ch) + ' & ' + chr(ch)
if ch == 32:
return ch
else:
for x in table_ascii:
if ((ord(x) - 65) * 17 + 12) % 26 + 65 == ch:
return x
def enc(ch):
if ch == 32:
return ch
else:
return ((ch - 65) * 17 + 12) % 26 + 65
answer = bytearray(map(dec, list(key)))
print 'answer : ' + answer
플래그 값은 auctf{static_or_dyn@mIc?_12923}
My friend just spent hours making this custom shell! He's still working on it so it doesn't have much. But we can do some stuff! He even built a custom access control list for controlling if you can access files.
Check it out!
nc challenges.auctf.com 30010
서버에 접속하면 간단한 인터프리터가 실행되는데 help
로 실행 가능한 명령어를 확인할 수 있다.
ls
로 acl.txt와 flag.txt를 확인할 수 있고, flag.txt에 대한 권한이 없기 때문에 write
로 acl.txt에 권한을 추가해주면 cat flag.txt
로 플래그값을 확인할 수 있다.
플래그 값은 auctf{h4_y0u_g0t_tr0ll3d_welC0m#_t0_pWN_l@nd}
https://velog.io/@woounnan/AUCTF2020-House-of-Made