본문 바로가기

System Hacking/CTF

CSAW 2014 pwn_500 xorcise






로컬에서 환경을 구성하고 풀었다.


uint32_t decipher(cipher_data *data, uint8_t *output)

{

    uint8_t buf[MAX_BLOCKS * BLOCK_SIZE];    

    uint32_t loop;

    uint32_t block_index;

    uint8_t xor_mask = 0x8F;


    memcpy(buf, data->bytes, sizeof(buf));

    if ((data->length / BLOCK_SIZE) > MAX_BLOCKS)

    {

        data->length = BLOCK_SIZE * MAX_BLOCKS;

    }


    for (loop = 0; loop < data->length; loop += 8)

    {

        for (block_index = 0; block_index < 8; ++block_index)

        {

            buf[loop+block_index]^=(xor_mask^data->key[block_index]);

        }

    }

    memcpy(output, buf, sizeof(buf));

}

decipher함수에 취약점이 존재한다. MAX_BLOCKS 는 16, BLOCK_SIZE 는 8 이므로

buf의 크기는 16*8 = 128이다.


if 조건절을 보면 (data->length/BLCOK_SIZE) > MAX_BLOCKS 일때 length를 128로 맞춰준다.

하지만 정수형을 나누는 것이므로..

length가 135라면 -> 135/8 = 16이 되므로 조건절을 통과하게 되어 7바이트 오버플로가 발생한다.


이 때 스택의 구조를 보면..



오버플로로 접근할 수 있는 부분은 0xbffff433~0xbffff439 까지이다.

RET는 0xbffff44c에 있으므로 RET를 접근하려면 변수를 이용해야 한다.


디스어셈블 코드를 분석해보면

스택은 buf(128바이트) - xor_mask(0x8f 1바이트) - block_index(4바이트) - loop(4바이트)로 되어있다.

7바이트 오버플로로 접근할 수 있는 부분은 loop의 2번째 바이트까지인데 뒤의 연산과정을 보면


buf[loop+block_index]^=(xor_mask^data->key[block_index])


이렇게 연산이 진행된다.

접근할 수 있는 loop나 block_index를 조작한다면 특정 위치의 값에 접근이 가능할 것이다.


그리고 반복문에서 연산이 8바이트 단위로 진행되므로

xor_mask 1바이트, block_index 4바이트, loop 첫번쨰 바이트, 조작된 loop값을 통해 특정위치의 값에 2번 xor연산이 가능하다.

(2바이트 조작가능)


gdb에서 스택의 메모리를 찾아내, xor연산을 통해 조작할 값을 계산해 넣어주면 된다.


system으로 리턴시켰다가 잘안되길래 readfile()함수로 리턴시킴






이제 password.txt를 로컬에 만들어주고,

로컬파일으로부터 hash_checksumd을 얻어내 서버에 명령을 내린다고 가정해보면..










xorcise


xorcise.c