• XSS.stack #1 – первый литературный журнал от юзеров форума

Решение задания с pwnable.kr 11-coin1, 12-blackjack, 13-lotto. Ошибки в логике приложений

tabac

CPU register
Пользователь
Регистрация
30.09.2018
Сообщения
1 610
Решения
1
Реакции
3 332
Решение задания coin1

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

image


После подключения нам предлагают сыграть в игру и предоставляют правила игры. А также нам дают на прохождение 60 секунд, поэтому придется все автоматизировать.

image


По правилам игры нам дают 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)

image


Отлично. Теперь напишем часть, для прохождения одного уровня. Для этого нам понадобится массив значений от 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())

image


Теперь добавим это решение в цикл для прохождения всех уровней.
Код:
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())

image


Сдаем флаг и получаем очки.


Решение задания blackjack

Нажимаем на первую иконку с подписью coin1, и нам предоставляют адрес и порт для подключения. Еще сообщают, что нужно выиграть миллион.

image


После подключения нам предлагают сыграть в игру и спрашивают о готовности.

image


После нашего ответа, выходим в меню, начать игру, узнать правила или выйти из игры.

image


Начинаем новую игру.

image


Такие задания часто встречаются в CTF и о них полезно знать. Скорее всего отсутствует обработчик отрицательных чисел. Таким образом если ввести -999500 и проиграть, то из нашего банка вычтут отрицаельное число, то есть прибавлено положительное (500 — (-500) = 500 + 500 = 1000). Введем -1000000.

image


image


Сдаем флаг и получаем еще одно очко.

Решение задания lotto

Нажимаем на первую иконку с подписью lotto, и нам говорят, что нужно подключиться по SSH с паролем guest.

image


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

image


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

image


Давай просмотрим исход код.
Код:
#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 совпадений. Но проверка выполнена неправильно. Таким образом в цикле каждый символ введенной последовательности сравнивается с каждым символом сгенерированной.

image


Таким образом будем вводить 6 одинаковых символов каждый раз, пока не получим флаг. Я вводил !!!!!!, и на 7 раз получил флаг.

image


Сдаем флаг и получаем два очка.


автор @RalfHacker
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх