Arm32 execute & debugging env
음.. arm 바이너리에 대한 문제를 풀때마다 아주 환경때문에 곤혹을 치뤄서 이번에는 확실히 정리를 좀 해갈려고 한다.
일단, 오해가 있는게 “arm 바이너리를 실행할때 arm docker나 vm이 맞다” 라는 개념인데 내가 이번에 이걸 구현할려고 라즈베리파이도 해보고 arm32 ubuntu docker , arm32 devian docker 등 다 해보았지만, 결국 문제는 디버깅 환경 구축에 생긴다. 즉, 해당 환경을 만드는 건 쉽다. 근데 pwntools , pwndbg등을 붙일때 문제가 생긴다. 애초에 python을 다운로드 할때도 arm32 등의 버그가 정말 많았다.
그래서 이번에는 확실히 정리해가야 한다.
qemu-user로 하는게 맞다.
(pwn) amemoyoi ~$ pwd
/proc/sys/fs/binfmt_misc
(pwn) amemoyoi ~$ ls
python3.12 qemu-aarch64 qemu-arm qemu-loongarch64 qemu-mips64 qemu-mips64el qemu-ppc64le qemu-riscv64 qemu-s390x register status기존 서버에는 다음과 같이 모두 해놓았다. 즉, 이미 모든 아키텍쳐의 바이너리를 읽을 수 있게 설계를 해놓았다.
이제 문제는 해당 바이너리를 읽을 로더와 libc인데 이건 당연히 서버에서 구현하지 못한다 (충돌 , 오류 )
따라서, 우리는 일반적인 효율이 좋은 22.04 우툰투 docker를 만들고 해당 환경에 pwntools , dbg를 다운로드 받은뒤에 거기서 라이브러리와 로더를 다운로드하면 된다.
따라서 다음과 같이
#!/bin/bash
IMAGE_NAME=amemoyoi-ctf
CONTAINER_NAME=my_container
DOCKER_USER=$(grep -E '^ENV user ' Dockerfile | awk '{print $3}')
DOCKER_PORT=$(grep -E '^ENV chall_port ' Dockerfile | awk '{print $3}')
if [ -z "$DOCKER_PORT" ]; then
echo "[*] chall_port not found in Dockerfile. Using default: 10001"
DOCKER_PORT=10001
fi
#DOCKER_USER=deploy
# 1. Docker 이미지 빌드
docker build . -t $IMAGE_NAME
# 2. 기존 컨테이너 삭제 (있다면)
docker stop $CONTAINER_NAME 2>/dev/null
docker rm $CONTAINER_NAME 2>/dev/null
# 3. 새로운 컨테이너 실행 (권한 부여 및 네트워크 설정)
docker run -d -t --privileged -p $DOCKER_PORT:$DOCKER_PORT --name=$CONTAINER_NAME $IMAGE_NAME
# docker run -d -t --privileged --name=$CONTAINER_NAME $IMAGE_NAME
# 컨테이너 내부 기본 libc 백업 (gdb에 의해 달라질 수 있으므로)
docker exec -it -u root $CONTAINER_NAME bash -c "
cp /lib/x86_64-linux-gnu/libc.so.6 /home/$DOCKER_USER/libc-backup.so.6 &&
chown $DOCKER_USER:$DOCKER_USER /home/$DOCKER_USER/libc-backup.so.6
"
# 4. 컨테이너 내 필수 패키지 설치 (GDB, Pwntools, Pwndbg)
docker exec -it -u root $CONTAINER_NAME bash -c "
apt-get update && apt-get install -y \
gdb \
python3 python3-pip python3-dev python3-setuptools python3-wheel python3-venv \
git wget curl vim socat tmux file &&
python3 -m venv /opt/pwnenv &&
source /opt/pwnenv/bin/activate &&
pip3 install --no-cache-dir --upgrade pip &&
pip3 install --no-cache-dir pwntools &&
pip3 install poetry==1.6.1 &&
export PATH=\"/root/.local/bin:\$PATH\" &&
git clone https://github.com/pwndbg/pwndbg /opt/pwndbg &&
cd /opt/pwndbg &&
git checkout 2024.08.29 &&
./setup.sh &&
echo 'set disassembly-flavor att' >> ~/.gdbinit
"
# 참고로 source /opt/pwnenv/bin/activate 을 쳐야 가상환경에 들어 갈 수 있음 -> 정상 사용가능
# 위에서 제외된 명단 오류등으로 인한
# echo 'source /opt/pwndbg/gdbinit.py' >> ~/.gdbinit
docker exec -it -u root $CONTAINER_NAME bash -c "
mkdir -p /home/$DOCKER_USER/.vscode-server &&
chown -R $DOCKER_USER:$DOCKER_USER /home/$DOCKER_USER/.vscode-server
"
docker exec -it -u root $CONTAINER_NAME bash -c "
touch /home/$DOCKER_USER/exploit.py
chown -R $DOCKER_USER:$DOCKER_USER /home/$DOCKER_USER/exploit.py"
# 6. 사용자 셸에 pwn alias 등록 및 즉시 적용
docker exec -it -u root $CONTAINER_NAME bash -c "
echo 'alias pwn=\"source /opt/pwnenv/bin/activate\"' >> /root/.bashrc &&
source ~/.bashrc
"
# 패키지 설치 (줄바꿈 이스케이프, update 포함)
docker exec -it -u root "$CONTAINER_NAME" bash -lc '
set -e
apt-get update
apt-get install -y \
qemu-user-static \
gcc-arm-linux-gnueabi \
gcc-arm-linux-gnueabihf
'
# 스크립트 작성 (HEREDOC, 마지막에 && 제거)
docker exec -it -u root "$CONTAINER_NAME" bash -lc "
cat > /home/$DOCKER_USER/librarysetting.sh <<'EOF'
# if armel binary
ln -s /usr/arm-linux-gnueabi/lib/ld-linux.so.3 /lib || true
ln -s /usr/arm-linux-gnueabi/lib/libc.so.6 /lib || true
# if armhf binary
ln -s /usr/arm-linux-gnueabihf/lib/ld-linux-armhf.so.3 /lib || true
ln -s /usr/arm-linux-gnueabihf/lib/libc.so.6 /lib || true
EOF
chown $DOCKER_USER:$DOCKER_USER /home/$DOCKER_USER/librarysetting.sh
"
# 5. 컨테이너에 root 사용자로 접속
docker exec -it -u root $CONTAINER_NAME bash
일반적인 dockerset 파일이지만 핵심은
# 패키지 설치 (줄바꿈 이스케이프, update 포함)
docker exec -it -u root "$CONTAINER_NAME" bash -lc '
set -e
apt-get update
apt-get install -y \
qemu-user-static \
gcc-arm-linux-gnueabi \
gcc-arm-linux-gnueabihf
'다음과 같이 arm32용 라이브러리 ,로더를 설치한다는 것이다. 그리고 바이너리가 armel 이냐 armhf 냐에 따라서
ln -s /usr/arm-linux-gnueabi/lib/ld-linux.so.3 /lib || true
ln -s /usr/arm-linux-gnueabi/lib/libc.so.6 /lib || true을 하거나 (armel)
ln -s /usr/arm-linux-gnueabihf/lib/ld-linux-armhf.so.3 /lib || true
ln -s /usr/arm-linux-gnueabihf/lib/libc.so.6 /lib || true을 하면 된다.( armhf )
그러면 이제 실행하는 것은 어차피 본 서버의 커널에서 하니깐,
./arm_training-last해석이 가능하므로 굳이 qemu-arm 를 안붙여서 다음과 같이 하면 된다.
pwntools & dbg
exploit_arm.py 파일을 “~/pwn_env/Dockerfile_template/arm_env 에 만들어놓았다. 그대로 docker를 올리면 된다.
핵심 부분을 말하자면,
elif is_local == 3 :
# p = process(fname)
p = process(fname , env={ 'LD_PRELOAD' : './libc.so.6' , 'QEMU_GDB' : '1234' } )디버깅 부분이 다음과 같이 'QEMU_GDB' : '1234' 가 추가 되었다.
이를 통해서
다른 터미널에서
gdb-multiarch 를 실행한뒤
target remote localhost:1234
을 입력하면 붙일 수 있다.