puts - fake stdout 을 이용한 exploit
by St1tch크리스마스 ctf 문제에 stdout과 puts함수를 이용해서 쉘을 획득하는 문제가 있었다.
뭐 다음에 사용할지 안 할지 모르나 그냥 생각난김에 써놓는다.
64bit 기준 puts 함수 내에는 call QWORD PTR[rax+0x38] 부분이 존재한다.
이 부분과 stdout버퍼주소 변조를 이용해서 원하는함수를 실행할 수 있다.
이 방법은 fake stdout버퍼에 대략 0x110바이트 쓸 수 있어야한다.
함수를 분석해보면
첫번째 인자를 r12레지스터에 복사하고
r12레지스터의 값을 rsi에 넣는 과정이 있다.
그리고 r12를 제어할 수 있는 상황이 puts함수 내에는 딱히 없어보인다.
따라서 제어가능한 rdi레지스터만 이용해서 함수를 호출할 수 있다.
즉, 인자가 한개이하인 함수를 한번 호출할 수 있다.
여기서 원하는 함수를 호출하려면 몇가지 조건을 맞춰줘야한다.
우선 puts+73부분에서 zero플래그가 1이 되서 puts+83으로 넘어가야 한다.
puts+33을 통과하기 위해서는 stdout주소, 즉 stdout을 overwrite 하는주소를 변조해야한다.
예를 들어 0x~~30으로 안되면 0x~~20으로 바꿔보면 된다. 이런식으로 되는 주소를 찾으면 된다.
puts+55를 통과하기위해서는 변조된 overwrite주소 + 0x88에 유효한 주소가 있어야한다.
위에서 유효한주소를 써서 인터럽트가 발생하지 않으면, 변조된 주소이기 때문에 왠만해서는 cmp문은 무난하게 넘어갈 수 있다.
+83에서 zero플래그가 셋되서 +110으로 점프해야한다.
rdx는 변조된 stdout주소 + 0x88에 있는 값이다.
변조되지 않은 값에는 stdout주소 + ? 정도 값이 들어있다.
여기서는 그냥 바이너리 실행시켜보고 비교한뒤 적절한 값을 넣는게 제일 정확한거 같다.
+110으로 넘어가면 쭉 실행되다가 +140에서 +248로점프를 해야한다.
여기서 +117 부분이 중요한데 여기서 rdi, 즉 함수의 첫번째 인자를 정하는데,
다음 분기분들을 위해 몇가지 고려할 사항이있다.
첫번째는, eax에 rdi+0xc0의 값이 들어가는데
+248의 조건을 만족하려면 rdi+0xc0에도 0xffffffff 값이 있어야한다.
이 조건을 만족하면 이제 마지막 분기인 +152로 점프를 한다.
여기서는 +165부분, 즉 함수가 호출되는 부분이 중요한데,
rdi+0xd8이, 호출을 원하는 함수의 주소가 있는 주소 - 0x38이어야한다.
그래야 rax+0x38에서 원하는 함수가 호출되기 때문이다.
여기 까지 만족하면, 인자가 한개 이하인 원하는 함수를 한번 호출할 수 있다.
블로그의 정보
튜기's blogg(st1tch)
St1tch