memcpy(&ret, &(argv[1][44]), 4): argv[1][44]부터 4바이트를 복사해서 &ret에 저장한다.
=>argv[1][44]부터 4byte는 0-39 buffer 40-43 sfp 44-47 ret이므로 return address에 해당한다.
if(ret != execve_addr): 이 주소가 execve_addr(execve 주소)와 다르면 종료한다.
=> ret에는 execve의 주소만 들어갈 수 있다.
#execve()의 주소
System() 함수의 주소를 구할 때와 똑같이, call 시점에서의 주소는 실행 후 execve()의 주소가 아니므로 main에서 breakpoint를 잡고 run을 해서 실행시킨 후 print execve를 하면 실행 후 execve() 함수의 주소를 구할 수 있다.
실행 후 execve() 함수의 address: 0x400a9d48
#”/bin/sh”가 위치한 주소
“/bin/sh”가 위치한 주소: 0x400fbff9
#payload 작성
Payload 작성할 때, ret에는 execve() 주소를 넣으면서 system() 함수를 사용하는 방법이 있다.
Buffer+sfp(44) + ret(&execve) + execve()의 ret(&system) + dummy(4) + &”/bin/sh”
Ret에 &execve가 들어가면 RET을 하면서 ebp가 된다. 따라서
Execve()에서 Sfp + ret 이렇게 되는데 ret은 ebp+4가 되고 이 ret에 또 &system을 넣게 되면 RET하면서 ebp가 가리키게 되고, ebp + 4에 ret, ebp + 8에 인자가 위치하게 된다. System()에서의 ret은 dummy를 넣고(사용하지 않으므로) ebp + 8에서 argument가 처리되므로 여기에 “/bin/sh”의 주소를 넣어주면 system이 “/bin/sh”를 인자로 받아 쉘이 실행될 수 있게 된다.
여기서 주의해야 할 것은 python 명령을 “”으로 묶어주어야 한다는 것이다.
왜나하면 execve()의 주소에 “\x0a”를 포함하는데, ‘\n’(newline)을 의미해서 사용하면 \x00처럼 페이로드를 끊게 된다. 따라서 페이로드의 끊김을 막기 위해 “”을 사용하는 것이다.
하지만 \x00과 다른 점은, 더블 쿼터 “”로 감싸줌으로써 \n도 인자의 일부로 포함시킬 수 있다는 것이다.
성공!
"one step closer"
[LOB] level 16: assasin -> zombie_assassin (0) | 2019.06.26 |
---|---|
[LOB] level 15: giant -> assassin (0) | 2019.06.26 |
[LOB] level 13: darkknight -> bugbear (0) | 2019.05.15 |
[LOB] level 12: golem -> darkknight (0) | 2019.05.15 |
[LOB] level 11: skeleton -> golem (0) | 2019.05.15 |