Swing'Blog 浮生若梦 Swing'Blog 浮生若梦
  • Home
  • |
  • About
  • |
  • Articles
  • |
  • RSS
  • |
  • Categories
  • |
  • Links

Docker for Mac and gdb GUI windows

2018-12-10 Updated on 2020-06-23 环境配置

Table of Contents

  1. XQuartz
  2. Docker
  • Go!
    1. Set run docker script
  • Docker for Mac and GUI applications and gdb GUI windows

    我为啥有这需求呢? 以前 Pwntools + gdb.attach 进行调试的时候我用过一段时间的 tmux

    像下面这样:

    先在 Python 脚本加上 context.terminal = ['tmux', 'splitw', '-h']

    顺便一提我 tmux 的设置如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    set -g prefix C-a
    set -g default-terminal "screen-256color"
    set-window-option -g mode-keys vi
    bind h select-pane -L
    bind j select-pane -D
    bind k select-pane -U
    bind l select-pane -R
    unbind %
    bind \ split-window -h
    bind - split-window -v
    set -g mouse-utf8 on
    set -g mouse on

    unbind C-b

    # bind a reload key
    bind R source-file ~/.tmux.conf ; display-message "Config reloaded.."

    set-option -g mouse on

    其实这样看起来也不错啦~~~

    由于后来我用起了 Docker 然后我就开始想能不能在 docker 里往外面弹一个 gdb 调试窗口…然后就有了这个想法:

    XQuartz

    首先 我们需要 XQuartz

    brew cask install xquartz

    XQuartz 主要作为一个新终端的承载器和 host 机器和 Docker 的通讯器。

    Docker

    准备好你的Docker 由于我这主要用来调试一些 Pwn 题,所以我会有自己的依赖支持,比如 Pwntools 、onegadget 之类的东西…安装啥的我就不说了 环境可参考我的 Dockerfile

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    FROM ubuntu:18.04

    # Apt packages

    RUN sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list
    RUN apt-get clean

    RUN dpkg --add-architecture i386 && apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt-get install -y \
    git nasm python \
    build-essential \
    python-dev python-pip python-setuptools \
    libc6-dbg \
    libc6-dbg:i386 \
    gcc-multilib \
    gdb-multiarch \
    gcc \
    wget \
    curl \
    glibc-source \
    cmake \
    python-capstone \
    socat \
    netcat \
    ruby \
    lxterminal \
    fish
    # apt-get clean && \
    # rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
    # cd ~ && tar -xvf /usr/src/glibc/glibc-2.23.tar.xz

    # python/ruby packages & gdb-plugin
    RUN pip install --no-cache-dir pwntools ropper ancypatch swpwn && \
    gem install one_gadget && \
    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

    # git installaing package
    # RUN cd ~/ && \
    # git clone https://github.com/pwndbg/pwndbg.git && \
    # cd ~/pwndbg/ && ./setup.sh && \
    # rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

    RUN cd ~/ && \
    git clone https://github.com/longld/peda.git && \
    echo "source ~/peda/peda.py" >> ~/.gdbinit

    RUN cd ~/ && \
    git clone https://github.com/scwuaptx/Pwngdb.git && \
    cp ~/Pwngdb/.gdbinit ~/




    ENV LANG C.UTF-8

    VOLUME ["/pwn"]
    WORKDIR /pwn

    CMD ["/bin/bash"]

    Go!

    在终端里运行 XQuartz 并设置:

    open -a XQuartz

    Set run docker script

    这里我选择一个轻量的终端:lxterminal , 在Docker 里安装这个终端(Dockerfile 里已经有),然后获取当前 HOST 机器的 IP

    ip=$(ifconfig en0 | grep inet | awk '$1=="inet" {print $2}')

    接着只要设置容器内环境变量即可:

    docker run -d --name pwn -e DISPLAY=$ip:0 -v /tmp/.X11-unix:/tmp/.X11-uni

    当然这里咱们可以选择用脚本一键管理 : ancypwn

    此外在 Python script 上还得加上 context.terminal = ["lxterminal", "-e"]

    或者我这里进行了轻量魔改,脚本见最后,先看一眼效果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    #!/usr/bin/env python3
    from __future__ import print_function
    import argparse
    import os
    import os.path
    import docker
    import sys
    import json
    import subprocess as sp

    from distutils.dir_util import mkpath



    EXIST_FLAG = '/tmp/ancypwn.id'
    SUPPORTED_UBUNTU_VERSION = [
    # '14.04', Still many issues to be solved (version problems mostly)
    '16.04',
    '18.10',
    '18.04',
    ]

    client = docker.from_env()
    container = client.containers
    image = client.images


    class InstallationError(Exception):
    pass

    class UnsupportedUbuntuVersion(Exception):
    pass

    class AlreadyRuningException(Exception):
    pass

    class NotRunningException(Exception):
    pass

    class ColorWrite(object):
    COLOR_SET = {
    'END': '\033[0m',
    'yellow': '\033[38;5;226m',
    'red': '\033[31m',
    'blue': '\033[34m',
    'magenta': '\033[35m',
    'cyan': '\033[36m',
    }

    @staticmethod
    def color_write(content, color):
    print(ColorWrite.COLOR_SET[color] + content + ColorWrite.COLOR_SET['END'])

    def colorwrite_init():
    for color in ColorWrite.COLOR_SET:
    # Use default value for lambda to avoid lazy capture of closure
    setattr(ColorWrite, color, staticmethod(lambda x, color=color: ColorWrite.color_write(x, color)))

    # Static initialize ColorWrite
    colorwrite_init()

    def parse_args():
    """Parses commandline arguments
    Returns:
    args -- argparse namespace, contains the parsed arguments
    """
    parser = argparse.ArgumentParser(
    description="Anciety's pwn environment"
    )
    subparsers = parser.add_subparsers(
    help='Actions you can take'
    )

    run_parser = subparsers.add_parser(
    'run',
    help='run a pwn thread'
    )
    run_parser.add_argument(
    'directory',
    type=str,
    help='The directory which contains your pwn challenge'
    )
    run_parser.add_argument(
    '--ubuntu',
    type=str,
    help='The version of ubuntu to open'
    )
    run_parser.set_defaults(func=run_pwn)

    run_parser.add_argument(
    '--priv',
    action='store_true',
    help='privileged boot, so you can use something like kvm'
    )

    attach_parser = subparsers.add_parser(
    'attach',
    help='attach to running thread',
    )
    attach_parser.set_defaults(func=attach_pwn)

    end_parser = subparsers.add_parser(
    'end',
    help='end a running thread'
    )
    end_parser.set_defaults(func=end_pwn)


    args = parser.parse_args()
    if vars(args) != {}:
    args.func(args)
    else:
    parser.print_usage()


    def _get_terminal_size():
    p = sp.Popen('tput cols', shell=True, stdout=sp.PIPE)
    def _print_warning():
    print('Warning: Unable to get terminal size, you need to specify terminal size ' +
    'manually or your command line may behave strangely')
    if p.returncode != 0:
    _print_warning()
    return None, None
    cols = int(p.stdout)
    p = sp.Popen('tput lines', shell=True, stdout=sp.PIPE)
    if p.returncode != 0:
    _print_warning()
    return None, None
    rows = int(p.stdout)
    return cols, rows


    def _read_container_name():
    if not os.path.exists(EXIST_FLAG):
    raise Exception('Pwn thread is not running')

    container_name = ''
    with open(EXIST_FLAG, 'r') as flag:
    container_name = flag.read()

    if container_name == '':
    os.remove(EXIST_FLAG)
    raise Exception('Meta info corrupted, or unable to read saved info. ' + \
    'Cleaning corrupted meta-info, please shutdown container manually')

    return container_name

    def _attach_interactive(name):
    cols, rows = _get_terminal_size()
    if rows and cols:
    cmd = "docker exec -it {} bash -c \"{}\"".format(
    name,
    'stty cols {} && stty rows {} && bash'.format(
    cols,
    rows,
    )
    )
    else:
    cmd = "docker exec -it {} '/bin/bash'".format(
    name,
    )

    ColorWrite.yellow(
    '''
    ______ _____ __ ___
    | __ \.--.--.--..-----.| |_ |__|.' _|.-----.
    | __/| | | || || || || _|| -__|
    |___| |________||__|__||_______||__||__| |_____|

    '''
    )
    os.system(cmd)


    def run_pwn(args):
    """Runs a pwn thread
    Just sets needed docker arguments and run it
    """
    if not args.ubuntu:
    ubuntu = '16.04'
    else:
    # check for unsupported ubuntu version
    if args.ubuntu not in SUPPORTED_UBUNTU_VERSION:
    raise UnsupportedUbuntuVersion('version %s not supported!' % args.ubuntu )
    ubuntu = args.ubuntu
    if not args.directory.startswith('~') and \
    not args.directory.startswith('/'):
    # relative path
    args.directory = os.path.abspath(args.directory)

    if not os.path.exists(args.directory):
    raise IOError('No such directory')

    if os.path.exists(EXIST_FLAG):
    raise AlreadyRuningException('Another pwn thread is already running')

    privileged = True if args.priv else False

    # First we need a running thread in the background, to hold existence
    try:
    os.system('xhost +')
    idx = os.popen('ifconfig en0').read().find('inet ')
    ip = os.popen('ifconfig en0').read()[idx+5:idx+19]
    running_container = container.run(
    'swpwn:{}'.format(ubuntu),
    '/bin/bash',
    cap_add=['SYS_ADMIN', 'SYS_PTRACE'],
    detach=True,
    tty=True,
    volumes={
    os.path.expanduser(args.directory) : {
    'bind': '/pwn',
    'mode': 'rw'
    },
    os.path.expanduser('~/.Xauthority') : {
    'bind': '/root/.Xauthority',
    'mode': 'rw'
    },
    os.path.expanduser('/tmp/.X11-unix') : {
    'bind': '/tmp/.X11-unix',
    'mode': 'rw'
    }
    },
    privileged=privileged,
    network_mode='host',
    environment={
    'DISPLAY': ip+':0'
    # 'DISPLAY': os.environ['DISPLAY']
    }
    )
    except Exception as e:
    print('This maybe caused by not completely installed ancypwn.')
    print('Have you read https://github.com/Escapingbug/ancypwn?')
    print()
    raise e

    # Set flag, save the container id
    with open(EXIST_FLAG, 'w') as flag:
    flag.write(running_container.name)


    # Then attach to it, needs to do it in shell since we need
    # shell to do the input and output part(interactive part)
    _attach_interactive(running_container.name)


    def attach_pwn(args):
    """Attaches to a pwn thread
    Just sets needed docker arguments and run it as well
    """
    container_name = _read_container_name()

    # FIXME Is it better that we just exec it with given name?
    conts = container.list(filters={'name':container_name})
    if len(conts) != 1:
    raise InstallationError('Installation seems to be run. There are more than one image called ancypwn')
    _attach_interactive(conts[0].name)


    def end_pwn(args):
    """Ends a running thread
    """
    container_name = _read_container_name()
    conts = container.list(filters={'name':container_name})
    if len(conts) < 1:
    os.remove(EXIST_FLAG)
    raise NotRunningException('No pwn thread running, corrupted meta info file, deleted')
    conts[0].stop()
    conts[0].remove()
    os.remove(EXIST_FLAG)
    # os.system('docker rm '+conts[0])



    def main():
    parse_args()


    if __name__ == "__main__":
    main()
    分类: 环境配置
    标签: pwn Docker
    ← Prev 35C3 CTF 2018 - collection (pwn)
    Next → GeekPwn 参赛记

    Comments

    © 2015 - 2026 Swing
    Powered by Hexo Hexo Theme Bloom