Läskeblask

Kategori

Rev

Beskrivning

Harriet hittar en lösenordskyddad fil och en post-it-lapp med vad som verkar vara ett lösenord. I sin iver att fort knappa in lösenordet, råkar hon spilla läskeblask över satellitens modermodem!

– Nåja, säger hon tyst för sig själv. Det där är Kenneths problem.

Föga anade hon att det strax skulle bli hennes problem också.

Lösenordet visade sig nämligen inte längre fungera. Aj då. Det måste ha kommit kolsyra i filsystemet.

Vad gör jag nu?! tänkte Harriet.

Hjälp Harriet genom att skicka in rätt lösenord till undutmaning-laskeblask.chals.io:443.

Lösning

Öppnar vi den bifogade binären i IDA så kan vi se hur funktionen main ser ut.

int __fastcall main(int argc, const char **argv, const char **envp)
{
  int i; // [rsp+1Ch] [rbp-E4h]
  int fd; // [rsp+20h] [rbp-E0h]
  char *v6; // [rsp+28h] [rbp-D8h]
  char buf[64]; // [rsp+30h] [rbp-D0h] BYREF
  char s[136]; // [rsp+70h] [rbp-90h] BYREF
  unsigned __int64 v9; // [rsp+F8h] [rbp-8h]

  v9 = __readfsqword(0x28u);
  setvbuf(stdout, 0, 2, 0);
  printf("Accessing flag");
  for ( i = 0; i <= 7; ++i )
  {
    usleep(0x186A0u);
    putchar('.');
  }
  puts("\nMust have password:");
  fgets(s, 128, stdin);
  v6 = strchr(s, '\n');
  if ( v6 )
    *v6 = 0;
  if ( checkpassword(s) )
  {
    fd = open("flag.txt", 0);
    if ( fd == -1 )
    {
      perror("open");
      exit(1);
    }
    memset(buf, 0, sizeof(buf));
    if ( (unsigned int)read(fd, buf, 0x3Fu) == -1 )
    {
      perror("read");
      exit(1);
    }
    puts("Correct password entered");
    printf("Have a flag!\n%s\n", buf);
    close(fd);
  }
  else
  {
    puts("Wrong pasword");
  }
  return 0;
}

Här ser vi att programmet läser in ett lösenord från användaren, skickar vidare det till funktionen checkpassword. Är resultatet korrekt så öppnas filen flag.txt och innehållet skrivs ut.

Kollar vi på funktionen checkpassword så ser vi att den jämför inmatningen med en hårdkodad sträng.

_BOOL8 __fastcall checkpassword(const char *a1)
{
  return strcmp(a1, PASSWORD) == 0;
}
.data:0000000000004090                 public PASSWORD
.data:0000000000004090 ; char PASSWORD[]
.data:0000000000004090 PASSWORD        db 's3kr37p455w0rDMuStb3Unkn0wn',0
.data:0000000000004090                                         ; DATA XREF: checkpassword+13o

Startar vi programmet och skriver in lösenordet s3kr37p455w0rDMuStb3Unkn0wn så får vi dock ett meddelande om att lösenordet är felaktigt.

Accessing flag........
Must have password:
s3kr37p455w0rDMuStb3Unkn0wn
Wrong pasword

Nästa steg är att debugga programmet. Det kan vi göra genom att använda gdb.

Startar vi programmet i gdb och sätter en breakpoint på checkpassword så kan vi se att funktionen inte är som det såg ut i IDA.

pwndbg> b checkpassword
Breakpoint 1 at 0x17bf
pwndbg> r

Starting program: laskeblask
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Accessing flag........
Must have password:
TEST

Breakpoint 1, 0x00005555555557bf in checkpassword ()

────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]────────────────────────────────────────────────────
 ► 0x5555555557bf <checkpassword+4>     mov    qword ptr [rbp - 0x18], rdi       [0x7fffffffd798] => 0x7fffffffd830 ◂— 0x54534554 /* 'TEST'
*/
   0x5555555557c3 <checkpassword+8>     mov    rcx, qword ptr [rip + 0x2906]     RCX, [0x5555555580d0] => 0x55555555579a ◂— mov al, byte ptr
 [rdi] /* 0x1275062a8034078a */
   0x5555555557ca <checkpassword+15>    mov    rdx, qword ptr [rbp - 0x18]       RDX, [0x7fffffffd798] => 0x7fffffffd830 ◂— 0x54534554 /* 'T
EST' */
   0x5555555557ce <checkpassword+19>    lea    rsi, [rip + 0x28bb]               RSI => 0x555555558090 (PASSWORD) ◂— 0xe5eee9f5e7eee1d3
   0x5555555557d5 <checkpassword+26>    mov    rdi, rdx                          RDI => 0x7fffffffd830 ◂— 0x54534554 /* 'TEST' */
   0x5555555557d8 <checkpassword+29>    nop
   0x5555555557d9 <checkpassword+30>    nop
   0x5555555557da <checkpassword+31>    nop
   0x5555555557db <checkpassword+32>    nop
   0x5555555557dc <checkpassword+33>    nop
   0x5555555557dd <checkpassword+34>    nop
   0x5555555557d9 <checkpassword+30>    nop
   0x5555555557da <checkpassword+31>    nop
   0x5555555557db <checkpassword+32>    nop
   0x5555555557dc <checkpassword+33>    nop
   0x5555555557dd <checkpassword+34>    nop
   0x5555555557de <checkpassword+35>    mov    rax, rcx     RAX => 0x55555555579a ◂— mov al, byte ptr [rdi] /* 0x1275062a8034078a */
   0x5555555557e1 <checkpassword+38>    call   rax                         <0x55555555579a>

   0x5555555557e3 <checkpassword+40>    jmp    checkpassword+47            <checkpassword+47>   

Här ser vi att checkpassword anropar rax. Stegar vi in i rax så kan vi se hur kontrollen av lösenordet ser ut.

 ► 0x55555555579a                       mov    al, byte ptr [rdi]     AL, [0x7fffffffd830] => 0x54
   0x55555555579c                       xor    al, 0x80               AL => 212
   0x55555555579e                       sub    al, byte ptr [rsi]     AL => 1 (0xd4 - 0xd3)
   0x5555555557a0                     ✔ jne    0x5555555557b4              <0x5555555557b4>

Här ser vi att varje byte i inmatningen xoras med 0x80 och sedan subtraheras med en byte från PASSWORD. Om resultatet inte är 0 betyder det att lösenordet är felaktigt.

RSI pekar på PASSWORD och RDI pekar på inmatningen. För att få ut värdet på PASSWORD kan vi skriva ut minnet i gdb.

pwndbg> x/s 0x555555558090
0x555555558090 <PASSWORD>:      "\323\341\356\347\365\351\356\345\302\362\357\364\350\345\362\200Stb3Unkn0wn"

Nu kan vi skriva ett skript som utför operationerna på varje byte i PASSWORD.

#!/usr/bin/env python3

flag = b'\323\341\356\347\365\351\356\345\302\362\357\364\350\345\362\200Stb3Unkn0wn'

for i in range(len(flag)):
    val = flag[i] ^ 0x80
    if val == 0:
        print()
        exit()
    print(chr(val), end='')

Kör vi skriptet så får vi ut lösenordet SanguineBrother. Använder vi det lösenordet mot servern så får vi flaggan.

sc undutmaning-laskeblask.chals.io 443
(connected to undutmaning-laskeblask.chals.io:443 and reading from stdin)
Accessing flag........
Must have password:
SanguineBrother
Correct password entered
Have a flag!
undut{d0n7_trus7_d3c0mpil3rs}

n00bz

Home of the n00bz CTF team.


By n00bz, 2025-03-29