목록System (14)
Un_Woo
cobolt->goblin gets함수로 입력을 받는 프로그램이다. 이번에도 rtl을 이용해서 풀 것이다.
gremlin->cobolt 코드가 gremlin과 거의 같지만 버퍼의 크기가 훨씬 작다. strcpy로 인자를 버퍼에 넣는 프로그램이다. 이번에는 rtl을 이용해서 풀 것이다. main함수에 브레이크포인트를 걸어서 system함수의 주소를 알아냈다. system함수의 주소를 알아내는 것은 프로그램을 복사해야 가능하다. 그리고 /bin/sh의 주소를 알아내는 프로그램을 짜서 /bin/sh의 주소를 알아냈다. ret주소에 system주소를 넣고 그 인자로 /bin/sh를 넣어 쉘을 땄다.
gate->gremlin strcpy로 인자를 버퍼에 넣는 프로그램이다. 버퍼의 크기는 256이다. 그러므로 버퍼(256)+sfp(4)+ret(4)의 구조인 것을 알 수 있다. ret주소를 변경하여 쉘을 딸 수 있다. 먼저 shellcode라는 환경변수를 만들어 쉘코드를 넣었다. 그리고 환경변수의 주소를 출력하는 프로그램을 짜서 shellcode의 주소를 출력했다. 그 주소로 ret주소를 덮으면 쉘을 딸 수 있다.
asm 플래그의 이름이 매우 긴 것을 확인 할 수 있다. 이 프로그램은 seccomp때문에 입력할 때 시스템콜로 open, write, read만을 사용하는 코드를 넣어줘야 한다. 그래서 그 이외의 것을 입력하면 세그멘테이션 폴트가 뜬다. 이 문제를 풀기 위해서 pwntools에 포함된 shellcraft를 이용하여 open, write, read를 사용해 플래그를 읽을 것이다. 다음과 같은 코드로 플래그를 읽는 코드를 얻을 수 있다. 이것을 asm 파일에 입력해주면 된다.
cmd2 코드를 보면 환경변수를 사용하지만 모르므로 넘어간다… 인자로 받은 것을 system함수로 실행한다. 하지만 그 인자에서 =, PATH, export, /, `, flag가 있으면 실행되지 않는다. 그래서 저 문자들을 우회하기 위해서 노력했다. 이전 명령어를 실행하는 !!을 사용하거나…(!!을 system 명령으로 사용하려면 /bin을 붙여야 했다.) history 명령어로 /bin/cat flag인 3으로 실행을 한다던가…(/bin을 붙여야 했다.) 그래서 쉘 스크립트를 사용하여 명령어를 실행하기로 했다. /를 우회하기 위해서 /를 아스키코드 8진수로 변환한 \57로 입력했다. 16진수와 10진수는 되지 않았다. flag는 우회하기 위해서 *을 사용했다.
cmd1 환경변수를 사용하는 것 같은데 환경변수는 아는 것이 없기 때문에 다른 방법으로 풀었다. 아마 환경변수를 이용해서 푸는 방법도 있을 것 같다. 코드를 살펴보면 인자를 받는다. 그 인자를 filter함수에 넣어서 flag, sh, tmp가 들어가 있으면 프로그램을 종료시킨다. 그러므로 flag, sh, tmp를 인자로 넣지 않고 flag의 값을 확인해야 한다. 그래서 fla*을 해서 fla로 시작하는 모든 파일을 cat했다.
lotto 이 문제는 1~45의 숫자 6개로 조합된 랜덤한 값을 맞추는 문제이다. 하지만 이 부분을 보면 로또 1개의 값을 제출한 모든 숫자와 비교한다. 그러므로 제출한 6개의 숫자 중 하나라도 로또 번호 1개와 같다면 match변수가 6이 된다. ascii코드에섯 1~45 중 입력 가능한 것은 32~45 부분의 특수문자들이라고 생각했다. 물론 lotto값은 랜덤이므로 성공할 때까지 여러 번 해줘야 한다.
mistake 문제를 보면 무엇인가 실수를 했고 연산자 우선순위를 힌트로 줬다. 일단 실행을 해보니 두 번 입력을 받는 것을 알 수가 있다. 그리고 gdb에서도 실행시켜 봤는데 open 함수가 실패하여 -1을 리턴한 것으로 보인다. 그런데 can't open password 뒤에 1이 있는 것이 이해가 되지 않았다. 코드를 보면 그 뒤에 있어야 하는 것은 fd의 값인 -1이라고 생각했기 때문이다. 하지만 왜 1이 나오는지 이해를 못 하고 있었던 중 힌트였던 연산자 우선순위가 생각나 구글링을 해봤다. 그리고 코드에서 문자가 있는 부분은if(fd=open("/home/mistake/password",O_RDONLY,0400) < 0)이라고 생각했으므로 이 코드에 쓰인 =과
random random변수에 랜덤값을 받고 key에 값을 입력받아 두 개의 값을 ^연산자로 처리한 값이 0xdeadbeef면 flag를 열 수 있다. ^연산자는 XOR연산자이다. XOR연산자는 2진수로 봤을 때 두 값이 다르면 1, 같으면 0이 된다. 근데 여기서 rand()를 아무리 써봤자 값이 변하지 않는다. 시드값이 없기 때문이다. 값이 변하게 하려면 srand()를 써야한다. key은 rbp-0x8에 random은 rbp-0x4에 있다. 일단 random값을 알아보자. 어셈블리 코드를 보면 random값이 들어가 있는 레지스터가 eax인 것을 알 수 있다. 그러므로 eax에 값이 들어간 후에 break를 걸어보면... rax(eax)에 0x6b8b4567가 들어간 것을 알 수 있다. 0xdead..
passcode 이것이 전체적인 코드인데 이름을 입력받고 비밀번호를 2개 입력받아 비밀번호가 맞으면 flag가 열리는 프로그램이다. 그래서 그냥 비밀번호를 맞추면 되는 건가하고 생각했지만 ... 사진과 같이 segmentation fault가 뜬다. 그 이유는 무엇일까? 위 코드를 다시 자세히 보면 scanf를 사용할 때 변수들 앞에 &을 사용하지 않는 것을 볼 수 있다. &을 사용하지 않으면 scanf의 두 번째 인자를 주소로 인식한다고 한다. 예를 들면 scanf("%d",a)라고 하면 a를 변수로 인식하지 않고 주소로 인식하여 그 주소에 값을 넣는 것이다. 그리고 scanf를 사용한 것들을 보면 name은 ebp-70에 100만큼 입력, passcode1는 ebp-10에 4만큼 입력한다. 그러므로 ..