
В данной статье разберем решение многоуровнего задания с помощью библиотеки pwntools.
Организационная информация
Специально для тех, кто хочет узнавать что-то новое и развиваться в любой из сфер информационной и компьютерной безопасности, я буду писать и рассказывать о следующих категориях:
Вдобавок к этому я поделюсь своим опытом в компьютерной криминалистике, анализе малвари и прошивок, атаках на беспроводные сети и локальные вычислительные сети, проведении пентестов и написании эксплоитов.
Чтобы вы могли узнавать о новых статьях, программном обеспечении и другой информации, я создал канал в Telegram и группу для обсуждения любых вопросов в области ИиКБ. Также ваши личные просьбы, вопросы, предложения и рекомендации рассмотрю лично и отвечу всем.
Вся информация представлена исключительно в образовательных целях. Автор этого документа не несёт никакой ответственности за любой ущерб, причиненный кому-либо в результате использования знаний и методов, полученных в результате изучения данного документа.
- PWN;
- криптография (Crypto);
- cетевые технологии (Network);
- реверс (Reverse Engineering);
- стеганография (Stegano);
- поиск и эксплуатация WEB-уязвимостей.
Вдобавок к этому я поделюсь своим опытом в компьютерной криминалистике, анализе малвари и прошивок, атаках на беспроводные сети и локальные вычислительные сети, проведении пентестов и написании эксплоитов.
Чтобы вы могли узнавать о новых статьях, программном обеспечении и другой информации, я создал канал в Telegram и группу для обсуждения любых вопросов в области ИиКБ. Также ваши личные просьбы, вопросы, предложения и рекомендации рассмотрю лично и отвечу всем.
Вся информация представлена исключительно в образовательных целях. Автор этого документа не несёт никакой ответственности за любой ущерб, причиненный кому-либо в результате использования знаний и методов, полученных в результате изучения данного документа.
Решение задания input
Нажимаем на иконку с подписью input, и нам говорят, что нужно подключиться по SSH с паролем guest.

При подключении мы видим соотвтствующий баннер.

Давайте узнаем какие файлы есть на сервере, а также какие мы имеем права.
ls -l

Таким образом мы можем можем прочитать исходный код программы, так как есть право читать для всех, и выполнить с правами владельца программу input (установлен sticky-бит). Давай просмотрим исход код.
Исходный код input.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main(int argc, char* argv[], char* envp[]){
printf("Welcome to pwnable.kr\n");
printf("Let's see if you know how to give input to program\n");
printf("Just give me correct inputs then you will get the flag :)\n");
// argv
if(argc != 100) return 0;
if(strcmp(argv['A'],"\x00")) return 0;
if(strcmp(argv['B'],"\x20\x0a\x0d")) return 0;
printf("Stage 1 clear!\n");
// stdio
char buf[4];
read(0, buf, 4);
if(memcmp(buf, "\x00\x0a\x00\xff", 4)) return 0;
read(2, buf, 4);
if(memcmp(buf, "\x00\x0a\x02\xff", 4)) return 0;
printf("Stage 2 clear!\n");
// env
if(strcmp("\xca\xfe\xba\xbe", getenv("\xde\xad\xbe\xef"))) return 0;
printf("Stage 3 clear!\n");
// file
FILE* fp = fopen("\x0a", "r");
if(!fp) return 0;
if( fread(buf, 4, 1, fp)!=1 ) return 0;
if( memcmp(buf, "\x00\x00\x00\x00", 4) ) return 0;
fclose(fp);
printf("Stage 4 clear!\n");
// network
int sd, cd;
struct sockaddr_in saddr, caddr;
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd == -1){
printf("socket error, tell admin\n");
return 0;
}
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = INADDR_ANY;
saddr.sin_port = htons( atoi(argv['C']) );
if(bind(sd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0){
printf("bind error, use another port\n");
return 1;
}
listen(sd, 1);
int c = sizeof(struct sockaddr_in);
cd = accept(sd, (struct sockaddr *)&caddr, (socklen_t*)&c);
if(cd < 0){
printf("accept error, tell admin\n");
return 0;
}
if( recv(cd, buf, 4, 0) != 4 ) return 0;
if(memcmp(buf, "\xde\xad\xbe\xef", 4)) return 0;
printf("Stage 5 clear!\n");
// here's your flag
system("/bin/cat flag");
return 0;
}
Из кода следует, что нам необходимо пройти пять уровней. Будем проходить их по очереди.

На первом уровне проверяется, чтобы число аргументов программы равнялось 100. При этом 65-м элементом должна быть строка “\x00”, а 66-м — “\x20\x0a\x0d”. Создадим свою директорию в директории /tmp/ и там создадим питоновский скрипт.

Для решения первого уровня мы создадим массив из ста строк ‘A’. И присвоим нужным аргументам нужные значения. Запустить процесс с данными аргументами мы можем следующим образом:
from pwn import *
a = ['A']*100
a[0] = '/home/input2/input'
a[ord('A')] = '\x00'
a[ord('B')] = '\x20\x0a\x0d'
ex = process(argv=a)
ex.interactive()

Мы прошли первый уровень. Взглянем на второй.

На данном уровне происходит считывание двух строк, одной и стандартного ввода stdin, а другой — из stderr. Нам необходимо создать два файла, которые будут содержать эти строки.

Открыть потоки к этим файлам и указать в качестве дескриптора stdin дескриптор на поток одного файла, а в качестве дескриптора stderr — другого файла.
from pwn import *
a = ['A']*100
a[0] = '/home/input2/input'
a[ord('A')] = '\x00'
a[ord('B')] = '\x20\x0a\x0d'
fin = open('/tmp/ex/in.txt', 'r')
ferr = open('/tmp/ex/err.txt', 'r')
ex = process(argv=a, stdin=fin, stderr=ferr)
fin.close()
ferr.close()
ex.interactive()

Приступим к решению третьего уровня.

Функция getenv() возвращает значение переменной окружения, которое должно быть равно эталонному значению. Таким образом нужно создать переменную окружения с определенным значением.
from pwn import *
a = ['A']*100
a[0] = '/home/input2/input'
a[ord('A')] = '\x00'
a[ord('B')] = '\x20\x0a\x0d'
fin = open('/tmp/ex/in.txt', 'r')
ferr = open('/tmp/ex/err.txt', 'r')
e={'\xde\xad\xbe\xef':'\xca\xfe\xba\xbe'}
ex = process(argv=a, stdin=fin, stderr=ferr, env=e)
fin.close()
ferr.close()
ex.interactive()

С переменной окружения справились, теперь приступим с четвертому уровню.

По коду можем сказать, что программа открывает файл с именем “\x0a” и читает из него 4 символа, после чего сравнивает их с байтами “\x00”. Так как и сами символы, и название файла состоит из непечатуемых символов, то используем python.


Остался последний уровень. Приступим.

Программа открывает сокет на порте, указанном в 66-м аргументе. Потом принимает по сети 4 байта и сравнивает с эталонной строкой. Нам необходимо добавить в программу еще один аргумент — номер порта, установить соединение и послать необходимые 4 байта.
from pwn import *
a = ['A']*100
a[0] = '/home/input2/input'
a[ord('A')] = '\x00'
a[ord('B')] = '\x20\x0a\x0d'
a[ord('C')] = '1234'
fin = open('/tmp/ex/in.txt', 'r')
ferr = open('/tmp/ex/err.txt', 'r')
e={'\xde\xad\xbe\xef':'\xca\xfe\xba\xbe'}
ex = process(argv=a, stdin=fin, stderr=ferr, env=e)
fin.close()
ferr.close()
ex.interactive()


Вот и все, получаем свои очки.

До встречи в следующих статьях!
Мы в телеграм канале: канал в Telegram.