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

Статья [RU] Google CTF Quals 2019

NokZKH

Переводчик
Забанен
Регистрация
09.02.2019
Сообщения
99
Реакции
121
Пожалуйста, обратите внимание, что пользователь заблокирован
Я с нетерпением ждал Google CTF в этом году, потому что в прошлом году я не смог решить ни одной CTF. Три дня мучился, пытаясь разгадать печально известный «keygenme» (я был так близко). При входе в этот CTF я надеялся увидеть хотя бы один флаг, и я сделал это. Это немного, но я сделал это сам!

(sandbox) DevMaster 8000

image1.png


Нам предоставили платформу двоичного компоновщика, которая находилась в облаке, она была слегка изолированной. Существуют готовые файлы для подключения и использования платформы. Запустив шелл и проверив uid и gids, я заметил, что моя песочница все еще находится в корневой папке:

image3.png


Это открывает возможности, особенно если у нас есть suid-файлы. Внезапно, я нашел идеальный двоичный файл drop_privs в / home / user, который позволяет мне выполнять команды как любой пользователь:

image5.png


The flag is CTF{two-individually-secure-sandboxes-may-together-be-insecure}

(rev) Dialtone

image2.png


Декомпилируя с помощью GHIDRA, я увидел, что используются функции pulseaudio. Программа начинает запись в буфер, затем обрабатывает буфер в buffer2 в функции x, наконец, выполняет некоторые проверки для buffer2 в функции r и проверяет возвращаемое значение.

Код:
undefined8 main(undefined8 uParm1,undefined8 *puParm2)

{
  int iVar1;
  long paObj;
  undefined8 uVar2;
  uint *puVar3;
  char *pcVar4;
  undefined1 *puVar5;
  undefined buffer [32768];
  undefined buffer2 [131076];
  undefined4 local_24;
  undefined4 local_20;
  undefined local_1c;
  uint local_18;
  int ret;

  puVar5 = ss.3811;
  pcVar4 = "record";
  paObj = pa_simple_new(0,*puParm2,2,0,"record",ss.3811,0,0,&local_18);
  if (paObj == 0) {
    uVar2 = pa_strerror((ulong)local_18);
    fprintf(stderr,"pa_simple_new() failed: %s\n",uVar2);
    uVar2 = 1;
  }
  else {
    local_24 = 0;
    local_20 = 0;
    local_1c = 0;
    do {
      puVar3 = &local_18;
      iVar1 = pa_simple_read(paObj,buffer,0x8000);
      if (iVar1 < 0) {
        uVar2 = pa_strerror((ulong)local_18);
        fprintf(stderr,"pa_simple_read() failed: %s\n",uVar2);
        return 1;
      }
      x(buffer,buffer2,buffer2);
      ret = r(&local_24,buffer2,(int)buffer2,(char *)puVar3,(int)pcVar4,(int)puVar5);
      if (ret < 0) {
        fwrite("FAILED\n",1,7,stderr);
        return 1;
      }
    } while (ret != 0);
    fwrite("SUCCESS\n",1,8,stderr);
    pa_simple_free(paObj);
    uVar2 = 0;
  }
  return uVar2;
}

Функция x была слишком сложной для меня, поэтому я попытался сначала проанализировать r. Тогда я думал, что двоичный файл может анализировать частоты записей, и первое, что мне пришло в голову, это тоны DTMF. После проверки тоновых частот:

image4.png


и, увидев точные цифры в функции r, я понял, код должен быть последовательностью наборов DTMF. Исходя из этого, я декомпилировал и переименовал всю функцию:

Код:
void r(void *dialTone,void *buffer)

{
  bool bVar1;
  double lowFreq [4];
  double highFreq [5];
  int yCoord;
  double maxFreq2;
  int yCoordFinal;
  uint xCoord;
  double maxFreq;
  uint xCoordFinal;

  *(int *)dialTone = *(int *)dialTone + 1;
  if (*(int *)dialTone < 0x15) {
    highFreq[0] = (double)f(buffer,0x4b9);
    highFreq[1] = (double)f(buffer,0x538);
    highFreq[2] = (double)f(buffer,0x5c5);
    highFreq[3] = (double)f(buffer,0x661);
    xCoordFinal = 0xffffffff;
    maxFreq = 1.00000000;
    xCoord = 0;
    while ((int)xCoord < 4) {
      if (maxFreq < highFreq[(long)(int)xCoord]) {
        xCoordFinal = xCoord;
        maxFreq = highFreq[(long)(int)xCoord];
      }
      xCoord = xCoord + 1;
    }
    lowFreq[0] = (double)f(buffer,0x2b9);
    lowFreq[1] = (double)f(buffer,0x302);
    lowFreq[2] = (double)f(buffer,0x354);
    f(buffer,0x3ad);
    yCoordFinal = -1;
    maxFreq2 = 1.00000000;
    yCoord = 0;
    while (yCoord < 4) {
      if (maxFreq2 < lowFreq[(long)yCoord]) {
        yCoordFinal = yCoord;
        maxFreq2 = lowFreq[(long)yCoord];
      }
      yCoord = yCoord + 1;
    }
    if (*(char *)((long)dialTone + 8) == '\0') {
      if ((-1 < (int)xCoordFinal) && (-1 < yCoordFinal)) {
        xCoordFinal = yCoordFinal << 2 | xCoordFinal;
        bVar1 = false;
        switch(*(undefined4 *)((long)dialTone + 4)) {
        case 0:
          bVar1 = xCoordFinal == 9;
          break;
        case 1:
          bVar1 = xCoordFinal == 5;
          break;
        case 2:
          bVar1 = xCoordFinal == 10;
          break;
        case 3:
          bVar1 = xCoordFinal == 6;
          break;
        case 4:
          bVar1 = xCoordFinal == 9;
          break;
        case 5:
          bVar1 = xCoordFinal == 8;
          break;
        case 6:
          bVar1 = xCoordFinal == 1;
          break;
        case 7:
          bVar1 = xCoordFinal == 0xd;
          break;
        case 8:
          if (xCoordFinal == 0) {
            return;
          }
        }
        if (bVar1) {
          *(int *)((long)dialTone + 4) = *(int *)((long)dialTone + 4) + 1;
          *(undefined4 *)dialTone = 0;
          *(undefined *)((long)dialTone + 8) = 1;
        }
      }
    }
    else {
      if (((int)xCoordFinal < 0) && (yCoordFinal < 0)) {
        *(undefined *)((long)dialTone + 8) = 0;
        *(undefined4 *)dialTone = 0;
      }
    }
  }
  return;
}

Извлечение последовательности из оператора switch-case:

Код:
tones = [1,2,3,'A',4,5,6,'B',7,8,9,'C','*',0,'#','D']
for i in [9,5,10,6,9,8,1,0xd,0]:
  print(tones[i], end='')

859687201

Флаг CTF {859687201}

Источник: https://xss.pro
Переводчик статьи - https://xss.pro/members/177895/
 
Хороший перевод, только есть один совет тебе на будущее: используй более человеческий язык. Никто не говорит "двоичный файл". Просто бинарник, или "испольняемый файл", или что-то такое.
 


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