В данной статье рассмотрим решения 3-х заданий с сайта pwnable.kr.
Организационная информация
Специально для тех, кто хочет узнавать что-то новое и развиваться в любой из сфер информационной и компьютерной безопасности, я буду писать и рассказывать о следующих категориях:
Вдобавок к этому я поделюсь своим опытом в компьютерной криминалистике, анализе малвари и прошивок, атаках на беспроводные сети и локальные вычислительные сети, проведении пентестов и написании эксплоитов.
Чтобы вы могли узнавать о новых статьях, программном обеспечении и другой информации, я создал канал в Telegram и группу для обсуждения любых вопросов в области ИиКБ. Также ваши личные просьбы, вопросы, предложения и рекомендации рассмотрю лично и отвечу всем.
Вся информация представлена исключительно в образовательных целях. Автор этого документа не несёт никакой ответственности за любой ущерб, причиненный кому-либо в результате использования знаний и методов, полученных в результате изучения данного документа.
- PWN;
- криптография (Crypto);
- cетевые технологии (Network);
- реверс (Reverse Engineering);
- стеганография (Stegano);
- поиск и эксплуатация WEB-уязвимостей.
Вдобавок к этому я поделюсь своим опытом в компьютерной криминалистике, анализе малвари и прошивок, атаках на беспроводные сети и локальные вычислительные сети, проведении пентестов и написании эксплоитов.
Чтобы вы могли узнавать о новых статьях, программном обеспечении и другой информации, я создал канал в Telegram и группу для обсуждения любых вопросов в области ИиКБ. Также ваши личные просьбы, вопросы, предложения и рекомендации рассмотрю лично и отвечу всем.
Вся информация представлена исключительно в образовательных целях. Автор этого документа не несёт никакой ответственности за любой ущерб, причиненный кому-либо в результате использования знаний и методов, полученных в результате изучения данного документа.
Решение задания coin1
Нажимаем на иконку с подписью coin1, и нам предоставляют адрес и порт для подключения.
После подключения нам предлагают сыграть в игру и предоставляют правила игры. А также нам дают на прохождение 60 секунд, поэтому придется все автоматизировать.
По правилам игры нам дают N монет, каждая весом 10, кроме одной — ее вес 9. Нам дают количество шансов(раундов) C для одной игры. На каждом раунде мы посылаем индексы монет, и нам вовращают и суммарный вес. Таким образом, применяя бинарный поиск, мы найдем нужную монету.
Напишем код. Для начала установим соединение с сервером, примем и распарсим числа N и C.
from pwn import *
r = remote('pwnable.kr', 9007)
r.recv()
s = r.recv()
print(s)
n = int(s.split(' ')[0][2:])
c = int(s.split('=')[2].split('\n')[0])
print(n, c)
Отлично. Теперь напишем часть, для прохождения одного уровня. Для этого нам понадобится массив значений от 1 до N+1 и цикл из С шагов, на каждой итерации которого будет отправлять половину массива. Если возвращенный в ответе вес будет делиться на 10 без остатка, то наша монета в другой части массива. Таким образом, мы снова разделим другую половину и проделаем то же самое с ней, и т.д. пока не будет обнаружена та самая монета.
mas = range(1,n+1)
for i in range(c):
s = ""
if len(mas)==1:
mas.append(mas[0])
for j in mas[:len(mas)/2]:
s += (str(j)+" ")
print(s)
r.send(s+"\n")
nr = r.recv()
print(nr)
if int(nr) % 10:
mas = mas[:len(mas)/2]
else:
mas = mas[len(mas)/2:]
r.send(str(mas[0])+"\n")
print(r.recv())
Теперь добавим это решение в цикл для прохождения всех уровней.
from pwn import *
r = remote('pwnable.kr', 9007)
r.recv()
for level in range(1, 101):
s = r.recvline()
n = int(s.split(' ')[0][2:])
c = int(s.split('=')[2].split('\n')[0])
mas = range(1,n+1)
for i in range(c):
s = ""
if len(mas)==1:
mas.append(mas[0])
for j in mas[:len(mas)/2]:
s += (str(j)+" ")
r.send(s+"\n")
nr = r.recv()
if int(nr) % 10:
mas = mas[:len(mas)/2]
else:
mas = mas[len(mas)/2:]
r.send(str(mas[0])+"\n")
r.recvline()
if level%5==0:
print("Check "+str(level)+"/100")
print(r.recv())
Сдаем флаг и получаем очки.
Решение задания blackjack
Нажимаем на первую иконку с подписью coin1, и нам предоставляют адрес и порт для подключения. Еще сообщают, что нужно выиграть миллион.
После подключения нам предлагают сыграть в игру и спрашивают о готовности.
После нашего ответа, выходим в меню, начать игру, узнать правила или выйти из игры.
Начинаем новую игру.
Такие задания часто встречаются в CTF и о них полезно знать. Скорее всего отсутствует обработчик отрицательных чисел. Таким образом если ввести -999500 и проиграть, то из нашего банка вычтут отрицаельное число, то есть прибавлено положительное (500 — (-500) = 500 + 500 = 1000). Введем -1000000.
Сдаем флаг и получаем еще одно очко.
Решение задания lotto
Нажимаем на первую иконку с подписью lotto, и нам говорят, что нужно подключиться по SSH с паролем guest.
При подключении мы видим соответствующий баннер.
Давайте узнаем, какие файлы есть на сервере, а также какие мы имеем права.
Давай просмотрим исход код.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
unsigned char submit[6];
void play(){
int i;
printf("Submit your 6 lotto bytes : ");
fflush(stdout);
int r;
r = read(0, submit, 6);
printf("Lotto Start!\n");
//sleep(1);
// generate lotto numbers
int fd = open("/dev/urandom", O_RDONLY);
if(fd==-1){
printf("error. tell admin\n");
exit(-1);
}
unsigned char lotto[6];
if(read(fd, lotto, 6) != 6){
printf("error2. tell admin\n");
exit(-1);
}
for(i=0; i<6; i++){
lotto[i] = (lotto[i] % 45) + 1; // 1 ~ 45
}
close(fd);
// calculate lotto score
int match = 0, j = 0;
for(i=0; i<6; i++){
for(j=0; j<6; j++){
if(lotto[i] == submit[j]){
match++;
}
}
}
// win!
if(match == 6){
system("/bin/cat flag");
}
else{
printf("bad luck...\n");
}
}
void help(){
printf("- nLotto Rule -\n");
printf("nlotto is consisted with 6 random natural numbers less than 46\n");
printf("your goal is to match lotto numbers as many as you can\n");
printf("if you win lottery for *1st place*, you will get reward\n");
printf("for more details, follow the link below\n");
printf("http://www.nlotto.co.kr/counsel.do?method=playerGuide#buying_guide01\n\n");
printf("mathematical chance to win this game is known to be 1/8145060.\n");
}
int main(int argc, char* argv[]){
// menu
unsigned int menu;
while(1){
printf("- Select Menu -\n");
printf("1. Play Lotto\n");
printf("2. Help\n");
printf("3. Exit\n");
scanf("%d", &menu);
switch(menu){
case 1:
play();
break;
case 2:
help();
break;
case 3:
printf("bye\n");
return 0;
default:
printf("invalid menu\n");
break;
}
}
return 0;
}
В функции main() нет ничего интересного. Интереспредставляет функция play(), разобрав которую мы поймем логику работы программы. Сперва мы вводим 6 значений, потом программа псевдослучайно генерирует еще 6 в диапазоне (1-45), после чего эти две последовательности сравниваются. Флаг получаем приналичии 6 совпадений. Но проверка выполнена неправильно. Таким образом в цикле каждый символ введенной последовательности сравнивается с каждым символом сгенерированной.
Таким образом будем вводить 6 одинаковых символов каждый раз, пока не получим флаг. Я вводил !!!!!!, и на 7 раз получил флаг.
Сдаем флаг и получаем два очка. До встречи в следующих статьях!
Мы в телеграм канале: канал в Telegram.