Skip to content

Commit

Permalink
Add pwnlib.config module and documentation
Browse files Browse the repository at this point in the history
This adds functionality for user configuration files at ~/.pwn.conf
and /etc/pwn.conf.  Previously this was only used by the pwnlib.log
module, and was entirely undocumented.

This is now documented, and offers an easy mechanism for other parts
of the code to have extension points.
  • Loading branch information
zachriggle committed Feb 13, 2017
1 parent 8b8a50b commit f5e38fc
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 16 deletions.
4 changes: 4 additions & 0 deletions docs/source/config.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
:mod:`pwnlib.config` --- Pwntools Configuration File
====================================================

.. automodule:: pwnlib.config
1 change: 1 addition & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Each of the ``pwntools`` modules is documented here.
atexception
atexit
constants
config
context
dynelf
encoders
Expand Down
1 change: 1 addition & 0 deletions pwn/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from pwn.toplevel import *

pwnlib.args.initialize()
pwnlib.config.initialize()
pwnlib.log.install_default_handler()

log = pwnlib.log.getLogger('pwnlib.exploit')
Expand Down
55 changes: 55 additions & 0 deletions pwnlib/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
"""Allows per-user and per-host configuration of Pwntools settings.
The list of configurable options includes all of the logging symbols
and colors, as well as all of the default values on the global context
object.
The configuration file is read from ``~/.pwn.conf`` and ``/etc/pwn.conf``.
The configuration file is only read in ``from pwn import *`` mode, and not
when used in library mode (``import pwnlib``). To read the configuration
file in library mode, invoke :func:`.config.initialize`.
The ``context`` section supports complex types, at least as far as is
supported by ``pwnlib.util.safeeval.expr``.
::
[log]
success.symbol=😎
error.symbol=☠
info.color=blue
[context]
adb_port=4141
randomize=1
timeout=60
terminal=['x-terminal-emulator', '-e']
"""
from __future__ import absolute_import

import collections
import ConfigParser
import os

registered_configs = collections.defaultdict(lambda x: True)

def register_config(section, function):
"""Registers a configuration section.
Arguments:
section(str): Named configuration section
function(callable): Function invoked with a dictionary of
``{option: value}`` for the entries in the section.
"""
registered_configs[section] = function

def initialize():
"""Read the configuration files."""
c = ConfigParser.ConfigParser()
c.read(['/etc/pwn.conf', os.path.expanduser('~/.pwn.conf')])

for section in c.sections():
settings = dict(c.items(section))
registered_configs[section](settings)
16 changes: 16 additions & 0 deletions pwnlib/context/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@

import socks

from pwnlib.config import register_config
from pwnlib.device import Device
from pwnlib.timeout import Timeout


_original_socket = socket.socket

class _devnull(object):
Expand Down Expand Up @@ -1343,3 +1345,17 @@ def setter(*a, **kw):
with context.local(**{k:kw.pop(k) for k,v in kw.items() if isinstance(getattr(ContextType, k, None), property)}):
return function(*a, **kw)
return setter

# Read configuration options from the context section
def update_context_defaults(section):
# Circular imports FTW!
from pwnlib.util import safeeval
for key, value in section.items():
if key not in ContextType.defaults:
continue
if isinstance(ContextType.defaults[key], (str, unicode)):
value = safeeval.expr(value)

ContextType.defaults[key] = value

register_config('context', update_context_defaults)
28 changes: 12 additions & 16 deletions pwnlib/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
import time

from pwnlib import term
from pwnlib.config import register_config
from pwnlib.context import Thread
from pwnlib.context import context
from pwnlib.exception import PwnlibException
Expand Down Expand Up @@ -132,26 +133,21 @@
}


# permit setting logging colors from a configuration file
config = os.path.expanduser('~/.pwn.conf')
if os.path.exists(config):
c = ConfigParser.ConfigParser()
c.read([config])

for section in c.sections():
if section not in _msgtype_prefixes:
def read_log_config(settings):
for key, value in settings.items():
if '.' not in key:
continue

for key, value in c.items(section):
if key == 'color':
try:
_msgtype_prefixes[section][0] = getattr(text, value)
except AttributeError:
pass
msgtype, key = key.split('.', 1)

if key == 'color':
current = _msgtype_prefixes[msgtype][0]
_msgtype_prefixes[msgtype][0] = getattr(text, value, current)

elif key == 'symbol':
_msgtype_prefixes[section][1] = value
elif key == 'symbol':
_msgtype_prefixes[msgtype][1] = value

register_config('log', read_log_config)

# the text decoration to use for spinners. the spinners themselves can be found
# in the `pwnlib.term.spinners` module
Expand Down

0 comments on commit f5e38fc

Please sign in to comment.